我应该在Bash脚本中使用Shebang吗?

我应该在Bash脚本中使用Shebang吗?,bash,shell,sh,shebang,Bash,Shell,Sh,Shebang,我正在使用Bash $ echo $SHELL /bin/bash 从大约一年前开始,我停止在Bash脚本中使用Shebangs。可以 我从使用#中获益/bin/sh或#/bin/bash 更新:在某些情况下,文件仅被视为具有 例如,Shebang $ cat foo.sh ls $ cat bar.sh #!/bin/sh ls $ file foo.sh bar.sh foo.sh: ASCII text bar.sh: POSIX shell script, ASCII text e

我正在使用Bash

$ echo $SHELL
/bin/bash
从大约一年前开始,我停止在Bash脚本中使用Shebangs。可以 我从使用
#中获益/bin/sh
#/bin/bash

更新:在某些情况下,文件仅被视为具有 例如,Shebang

$ cat foo.sh
ls

$ cat bar.sh
#!/bin/sh
ls

$ file foo.sh bar.sh
foo.sh: ASCII text
bar.sh: POSIX shell script, ASCII text executable

脚本应始终以shebang行开头。如果脚本没有以此开头,那么它可能由当前shell执行。但这意味着,如果使用您的脚本的人运行的shell与您不同,则脚本的行为可能会有所不同。此外,这意味着脚本不能直接从程序运行(例如,C
exec()
系统调用,或
find-exec
),它必须从shell运行。

标头很有用,因为它指定了运行脚本时要使用的shell。例如,
#/bin/zsh
会将shell改为zsh而不是bash,在这里可以使用不同的命令

例如,指定以下内容:

使用#/bin/sh,大多数商业变体中的默认Bourne shell 对于UNIX,使脚本可移植到非Linux机器,但 牺牲Bash的特定功能


在类UNIX系统上,应该始终使用shebang行启动脚本。系统调用execve(负责启动程序)依赖于具有可执行头或shebang行的可执行文件

从FreeBSD的:

execve()系统调用将调用进程转换为新的
过程新进程是从一个普通文件构造的,该文件
名称由路径指向,称为新进程文件。
[...]
这个文件是
可执行对象文件,或解释器的数据文件。
[...]
解释器文件以以下形式的行开始:
#! 解释器[arg]
当解释器文件被执行时,系统实际上是执行的
指定的解释器。如果指定了可选参数,则它将成为
解释器的第一个参数,以及
execve'd文件成为第二个参数
同样,从以下方面:

execve()执行文件名指向的程序。文件名必须为 可以是二进制可执行文件,也可以是以 表格:

#!解释器[可选参数]
事实上,如果文件头中没有正确的“幻数”(如ELF头或
#!
),
execve
将失败,并出现ENOEXEC错误(同样来自FreeBSD的execve手册页):

[ENOEXEC]新流程文件具有适当的访问权限 权限,但其中有无效的幻数 标题


如果文件具有可执行权限,但没有shebang行,但看起来确实是文本文件,那么行为取决于您运行的shell

大多数shell似乎会启动自己的新实例并将其提供给文件,请参见下文

由于无法保证脚本是为该shell编写的,因此这可能会成功,也可能会失败

发件人:

在不理解`#!'的系统上脚本解释器会议
可以编译shell以模拟它;请参阅shell的版本
变量如果是,shell将检查文件的第一行,以确定
它的形式是`#!解释器arg…'。如果是,外壳将启动
具有给定参数的解释器,并将文件按标准格式提供给它
输入。
从FreeBSD的:

如果程序不是正常的可执行文件(即
不以ASCII表示为的“幻数”开头
“#!”,从execve(2)中得到一个ENOEXEC返回值),但似乎
如果是文本文件,shell将运行一个新的sh实例来解释它。
来自bash(1):

如果由于文件不是可执行格式而导致执行失败,
并且该文件不是一个目录,它被假定为一个shell脚本,一个
包含shell命令的文件。生成一个子shell来执行它。

您不能总是依赖于非标准程序(如bash)的位置。我在
/usr/bin
/usr/local/bin
/opt/fsf/bin
/opt/gnu/bin
中见过bash

因此,通常最好使用
env

#/usr/bin/env bash
如果希望脚本可移植,请使用
sh
而不是
bash

#/垃圾箱/垃圾箱
虽然POSIX等标准不能保证标准实用程序的绝对路径,但大多数类UNIX系统似乎在
/bin
中有
sh
,在
/usr/bin
中有
env
  • 如果您编写bash脚本,即包含bash的不可移植脚本,则应继续使用
    #/bin/bash
    shebang只是为了确保使用了正确的解释器。您不应该用
    #替换shebang/bin/sh
    因为bash将在POSIX模式下运行,所以某些脚本的行为可能会有所不同

  • 如果您编写可移植的脚本,即仅使用POSIX实用程序及其支持的选项编写脚本,您可能会继续使用
    #/您的系统上的bin/sh
    (即,
    /bin/sh
    是POSIX外壳的系统)

  • 如果您编写了严格符合POSIX标准的脚本,并将其分发到各种平台,并且您确信这些脚本只能从符合POSIX标准的系统中启动,那么您可能也可能应该删除POSIX标准中规定的shebang:

  • 其基本原理是POSIX标准没有强制要求
    /bin/sh
    成为符合POSIX的shell,因此没有可移植的方法来指定其在shebang中的路径。在第三种情况下,为了能够在无法运行shebangless可执行脚本的系统上使用'find-exec'语法,您只需在
    find /tmp -name "*.foo" -exec sh -c 'myscript "$@"' sh {} + 
    
       #! /bin/sh
    
    root@kali:~/Desktop# cat /etc/passwd
    root:x:0:0:root:/root:/bin/bash