关于 Bash 脚本中 Shebang 的趣事
哈喽大家好,我是咸鱼
不知道小伙伴们在写 Bash 脚本或者说看别人的 Bash 脚本的时候有没有注意过脚本的第一行
#!/bin/bash
Bash 脚本的第一行往往以 #! 开头,这一行称作 shebang 行
在 类 UNIX 系统中,shebang 行用来指定脚本的解释器路径,通常出现在第一行,格式如下
#! interpreter_path
shebang 行中开头 #! 字符的作用是告诉操作系统这不是一个普通二进制文件,而是需要通过解释器运行的东西
而这个解释器则通过 #! 字符后面来指定。例如 /bin/bash 表示使用 bash 解释器来执行该脚本文件
下面则是一些 Bash 脚本的 shebang 行,指定了不同的解释器
#! /usr/bin/perl
#! /usr/bin/awk
#! /usr/bin/python
那么这时候小伙伴们可能就会有疑问:我忘了加 shebang 行,脚本为什么还能执行?
如果一个脚本没有添加 shebang 行来指定解释器路径,则默认情况下系统会使用默认的 shell 来执行脚本,系统默认的 shell 可以通过下面的命令来查看
# 一般情况下默认的 shell 为bash
echo $SHELL
现在我们知道了 shebang 行的作用,那么我们现在来编写一个脚本并修改 shebang 行试试
test.sh 内容如下:
#!/bin/bash
echo Hello
先给 test.sh 脚本添加一下执行权限
chmod +x test.sh
接下来我们用几种方式来执行这个脚本

可以看到脚本都成功执行了
下面我们来改一下 shebang 行,将其改成其他命令
#!/usr/bin/ls -l
echo Hello
然后我们分别用几种方式来执行这个脚本

上面脚本执行的结果是不是看的一脸懵逼,说实话我一开始看到的时候也是很懵
我们先来看下这四种脚本执行方式的区别
- bash tesh.sh
这种方式执行脚本的原理是将 test.sh 作为参数传给 bash 解释器(命令)来执行,而不是 test,sh 自己来执行
这种方式执行脚本不需要给脚本文件添加执行权限、不需要写 shebang 行指定解释器路径,因为脚本是作为参数被传给 bash 来执行
- sh test.sh
这种执行脚本的方式跟上面的方式原理一样,都是将脚本作为参数传进去,只不过是这个方式用的是 sh 解释器(命令),而不是 bash
- /root/test.sh
这种是通过绝对路径去执行脚本,通过绝对路径来执行脚本就需要脚本拥有执行权限
当使用绝对路径来执行脚本时,操作系统需要知道该脚本文件所使用的解释器类型,这就需要依靠脚本文件中的 shebang 行
实际上你用绝对路径执行脚本的时候,如果里面定义了 shebang 行(例如 #! /bin/bash)
那么实际上跟下面的命令是一样的
/bin/bash /root/test.sh
在执行脚本的时候,操作系统会读取脚本的 shebang 行
如果你的 shebang 行是其他 Linux 命令而不是解释器,那么就会导致操作系统将你的 shebang 行当作命令,而你的脚本则是命令的参数
就好比上面的例子,我将 shebang 行改成了 #! /usr/bin/ls -l ,当我执行脚本的时候其实就是下面这样的
/usr/bin/ls -l /root/test.sh
这样会导致脚本无法执行
- ./test.sh
这种是通过相对路径去执行脚本,跟上面用绝对路径执行脚本方式是一样的,只不过区别是一个是相对路径一个是绝对路径
总结:
- shebang 行通常出现在 UNIX 系统的脚本当中,用来指定脚本的解释器路径,出现在第一行,以
#!开头 - 如果脚本里面没有定义 shebang 行,系统会去找默认的解释器,默认解释器用
echo $SHELL查看 - 用 bash 或者 sh 命令执行脚本的时候,其实是把脚本作为参数传给 bash 或 sh 命令了,这时候脚本可以不添加执行权限、可以不需要 shebang 行
- 如果用绝对路径或者相对路径的方式来执行脚本,需要脚本拥有执行权限,如果 shebang 行定义的不是解释器而是其他命令,就会导致脚本无法执行
附上参考链接:Shebang Shenanigans :: Linus Karlsson
关于 Bash 脚本中 Shebang 的趣事的更多相关文章
- grep 查找bash脚本中的注释代码
出于安全性的考虑,不建议在bash脚本中注释掉不使用的代码.也就是说如果某段代码不使用了,那么应该删除掉,而不是简单地注释掉.假如你突然意识到这一点,而以前并没有遵从这个原则,现在需要找出脚本中的注释 ...
- 如何在Bash脚本中引入alias
更多精彩内容,请关注微信公众号:后端技术小屋 alias的使用 在日常开发中,为了提高运维效率,我们会用alias(命令别名)来定义命令的简称.比如在~/.bash_profile中添加: alias ...
- bash 脚本中分号的作用
在Linux bash shell中,语句中的分号一般用作代码块标识 1.单行语句一般要用到分号来区分代码块.比如: weblogic@pmtest:/$if [ "$PS1" ] ...
- Bash脚本中的操作符
一.文件測试操作符 假设以下的条件成立将会返回真. -e 文件存在 -a 文件存在 这个选项的效果与-e同样. 可是它已经被"弃用"了, 而且不鼓舞使用. -f 表示这个文件是一个 ...
- Bash 脚本中的 set -euxo pipefail
有些开发人员会用Bash来实现很复杂的功能,就像使用别的高级语言一样.他可能觉得自己很牛逼但其他人早就想锤爆他了,Bash的可读性和可维护性远远低于任何高级语言.更要命的是,Bash并没有方便的调试工 ...
- 详解在bash脚本中如何获取自身路径
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 这是stac ...
- bash脚本中的普通数组和关联数组
1. 普通数组 bash支持一维数组(不支持多维数组),并且没有限定数组的大小.类似与C语言,数组元素的下标由0开始编号.获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0. ...
- linux 环境下bash脚本中找不到命令
mr.sh: line 1: HADOOP_CMD: command not found mr.sh: line 4: INPUT_FILE_PATH: command not found mr.sh ...
- bash脚本中使用选项 getopts
原文链接 : http://note.youdao.com/noteshare?id=0cf08484c7308c763726e63e9a638ff5&sub=EF6A110E2F3345E6 ...
- Linux下shell脚本中信号捕获和函数练习脚本之ping一个网段
该脚本主要的目的是练习在Linux bash脚本中捕获信号,顺便练习一下函数的使用,还有就是终止一个正在运行的程序后,该程序打开的文件的后续处理问题等等!脚本功能: ping一个网段内的IP,检测哪 ...
随机推荐
- python求列表中某个值第一次出现的位置
x=[2,1,1] print(x.index(1)) 结果为1
- rules验证数值大于0
[['mobile'],'number'],[['mobile'],'compare','compareValue' =>0,'operator' => '>']compare对比, ...
- Apache Ranger系列七:Hive 和 Spark 执行过程中的文件路径配置
背景:在使用Ranger鉴权的过程中,要求必须开启impersonation功能(即执行用户与提交用户保持一致,而不是统一代理的hive/spark).但是在执行的过程中,会需要在hdfs存储临时的文 ...
- 关于Windows10纯净启动的相关修改流程
关于纯净启动的相关流程 自动登录 打开命令提示符运行control userpasswords2后回车 在弹出的用户账户窗口中,取消勾选"要使用本计算机,用户必须输入用户名和密码" ...
- linux查看已知进程PID所在的目录
pwdx 命令 pwdx PID [was@CMTRMWAS1 ~]$ pwdx 31996 31996: /was/AppServer/profiles/AppSrv03
- [rk3568][buildroot] 移除RK3568 iodomain check
1. 问题背景 RK3568 基线代码默认会起一个服务监控RK3568 iodomain,该服务间隔性输出log信息: 由于该功能非必要,故选择移除该部分逻辑 2.解决方案 查看源码编译脚本,如下图所 ...
- Spring源码构建踩坑记录
1:Kotlin: warnings found and -Werror specified Kotlin将程序中的警告变更为错误导致的问题,只需要改变一下级别即可,注意看是那个模块的 解决方式:fi ...
- C/C++编译构建相关问题
名词辨析 GNU GNU's Not Unix!的递归缩写 一个自由的操作系统,起源于GNU计划,希望发展出一套完整的开放源代码操作系统来取代Unix 基本组成包括: GNU编译器套装(GCC) GN ...
- Linux耳机音响独立输出
记得之前在用Ubuntu系统的时候,耳机和音响(线缆输出和模拟耳机输出)只能单独插一个,如果两个设备同时插入主机,将会导致只能耳机输出,即使选择后置音响(线缆输出)也不会有声音.在Windows下,即 ...
- java多线程基础小白指南--关键字识别(start,run,sleep,wait,join,yield)
在学习java多线程基础上,会遇到几个关键字,理解并识别它们是掌握多线程的必备知识,下面,我将通过源码或者程序演示给出我对这几个关键字的理解,如果有不同意见,欢迎在评论区或者发私信与我探讨. 一.st ...