我们在 shell 脚本中,经常看到以下内容作为开头:
#!/bin/bash
这里 #! 被称为 shebang 或者 hasbang。shebang 在 shell 脚本中起着重要的作用,特别是在处理不同类型的 shell 时。
本文将介绍:
1)什么是 shebang;
2)它如何在shell脚本中扮演重要角色。
shell脚本中的shebang是什么
shebang 是指的符号 #! ,这种字符的组合在脚本第一行中使用时具有特殊意义,它用于指定默认情况下运行给定脚本的解释器。
所以,如果脚本的第一行是:
#!/bin/bash
这意味着解释器应该是 bash shell。如果第一行是:
#!/bin/zsh
这表示要使用的解释器是 Z shell。
在这里 #! 的用法当然是特殊的。因为 # 在 shell 脚本中是用于注释,在这里它有特殊的含义。
为什么 shebang 在 shell 脚本中很重要?
是这样的,shebang 后跟的 shell 可执行文件对于脚本来说不是强制性的。
如果我们写了这样一个简单的脚本:
echo "Hello,TIAP!"
赋予执行权限,使用 . 运行它,它将由当前登录的 shell 运行:
$ cat sampleecho "Hello,TIAP!"$ chmod u+x sample$ ./sampleHello,TIAP!
那么,为什么还要在 shell 脚本中添加 #!/bin/bash 这一行作为开头呢?
因为在 Linux 或者 Unix 系统中,有多个 shell 可用。虽然这些 shell 大多具有相同的语法,但它们还是有一些差别,在某些语法中有不同的处理方式。
所以,我们需要在脚本中指定正确的 shell 解释器。否则的话,某些脚本在不同的 shell 中运行,可能就会产生不同的结果。
下面我们来举个例子。
使用 shebang 指定 shell 解释器的重要性
我写了一个示例脚本,内容是将几个 Linux 发行版本的名称放到一个数组中,然后打印出数组中第2个元素。
distros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"
我没有添加 shebang 行来指定任何 shell 解释器。这意味着当我执行这个脚本时,它将由默认shell(在我们的例子中是bash)运行。
以下为输出:
$ cat arrays.shdistros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"$ echo $0bash$ ./arrays.shDistro at index 2 is: SUSE
在上面例子中,数组的第2个元素输出显示为 SUSE,因为在 bash 和许多其他编程和脚本语言中,数组索引是从 0 开始的。但是在 Z shell 中不是,Z shell 中数组的索引是从1开始。
我在系统中安装了 Z shell,然后更改脚本,在第一行添加 shebang,并指定脚本由 Z shell 运行:
#!/bin/zshdistros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"
以下为输出:
$ cat arrays.sh#!/bin/zshdistros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"$ ./arrays.shDistro at index 2 is: Fedora
看到区别了吧,相同的脚本却有不同的输出,这就是为什么要添加 shebang 来指定解释器的原因。作为系统管理员,在编写脚本的时候知道使用的是哪个 shell,但是不能确定脚本的运行环境是不是与编写环境使用相同的默认shell,所以,需要指定一个 shell。
如果运行时指定了 shell,那么 shebang 将会被忽略
前文中为什么要强调“默认”shell 呢?因为 shebang 指定了运行脚本的解释器。
但是,在运行的时候可以显示的指定 shell,这种情况下,shebang 将会被忽略:
$ ./arrays.shDistro at index 2 is: Fedora$ bash arrays.shDistro at index 2 is: SUSE
shebang 是怎样工作的?
当你在脚本的第一行使用 shebang 时,就是在告诉 shell 使用指定的命令运行脚本。
基本上,#/bin/zsh 相当于:
/bin/zsh script_name
我们前文中说过,如果脚本中第一行写了 shebang,这就意味着已经指定了 shell 解释器。
这其实是部分正确。事实上,这就是 shebang 存在的目的。但是 shebang 这一行不一定非要有可执行的 shell,它可以是任何东西。
比如,我们使用 #!/bin/cat 来代替 #!/bin/zsh,/bin/cat 是 cat 命令的可执行文件。
#!/bin/catdistros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"
那现在这个脚本将使用 cat 命令运行,并显示脚本的内容:
$ cat arrays.sh#!/bin/catdistros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"$ ./arrays.sh#!/bin/catdistros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"
只要它指定的是可执行命令,那么它就会正常运行。如果你放的是其他一些随机的东西,那么就会报错。
比如,我在 shebang 一行这样写:
#!/home/tiap
很显然,它指向的并不是一个可执行文件,因此会抛出一个错误的解释器错误:
$ cat arrays.sh#!/home/tiapdistros=("Ubuntu" "Fedora" "SUSE" "Debian")echo "Distro at index 2 is: ${distros[2]}"$ ./arrays.shbash: ./arrays.sh: home/tiap: bad interpreter: Permission denied
最后,我们再来明确几个注意事项:
1)在 # 和 ! 之间没有空格,不能这样写:# !/bin/bash;
2)大多数系统允许 #! 和 bin/bash 之间有空格,但是,作为一个好的习惯,还是不要在 #! 和 /bin/bash 之间添加空格;
3)#! 必须放在第一行,否则,shebang 将会被认为是一个注释,最好在它之前也不要有空行。
以上就是本次分享全部内容,欢迎讨论。




