bash - 我应该使用带有 Bash 脚本的 Shebang 吗?

标签 bash shell sh shebang

我正在使用 Bash

$ echo $SHELL
/bin/bash

从大约一年前开始,我停止在我的 Bash 脚本中使用 Shebangs。能 我受益于使用 #!/bin/sh#!/bin/bash?

更新:在某些情况下,文件仅被视为具有 舍邦,例子

$ 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

最佳答案

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

来自 FreeBSD 的 execve manual page :

 The execve() system call transforms the calling process into a new
 process.  The new process is constructed from an ordinary file, whose
 name is pointed to by path, called the new process file.
 [...]

 This file is
 either an executable object file, or a file of data for an interpreter.

 [...]

 An interpreter file begins with a line of the form:

       #! interpreter [arg]

 When an interpreter file is execve'd, the system actually execve's the
 specified interpreter.  If the optional arg is specified, it becomes the
 first argument to the interpreter, and the name of the originally
 execve'd file becomes the second argument

Linux manual page 类似:

execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form:

#! interpreter [optional-arg]

事实上,如果一个文件的头部没有正确的“魔数(Magic Number)”(比如 ELF 头部或 #!),execve 将 < em>因 ENOEXEC 错误而失败(同样来自 FreeBSD 的 execve 联机帮助页):

[ENOEXEC] The new process file has the appropriate access permission, but has an invalid magic number in its header.


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

大多数 shell 似乎会启动一个新的自身实例并将文件提供给它,见下文。

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

来自 tcsh(1) :

   On  systems which do not understand the `#!' script interpreter conven‐
   tion the shell may be compiled to emulate it;  see  the  version  shell
   variable.  If so, the shell checks the first line of the file to see if
   it is of the form `#!interpreter arg ...'.  If it is, the shell  starts
   interpreter  with  the  given args and feeds the file to it on standard
   input.

来自 FreeBSD 的 sh(1) :

If the program is not a normal executable file (i.e., if it
     does not begin with the “magic number” whose ASCII representation is
     “#!”, resulting in an ENOEXEC return value from execve(2)) but appears to
     be a text file, the shell will run a new instance of sh to interpret it.

来自 bash(1):

   If this execution fails because the file is not in  executable  format,
   and  the file is not a directory, it is assumed to be a shell script, a
   file containing shell commands.  A subshell is spawned to  execute  it.

您不能总是依赖于非标准程序(如 bash)的位置。我在 /usr/bin/usr/local/bin/opt/fsf/bin/中看到了 bash选择/gnu/bin 仅举几例。

所以通常使用env是个好主意;

#!/usr/bin/env bash

如果您希望脚本可移植,请使用 sh 而不是 bash

#!/bin/sh

虽然像 POSIX 这样的标准不保证标准实用程序的绝对路径,但大多数类 UNIX 系统似乎在 /bin 中有 shenv/usr/bin 中。

关于bash - 我应该使用带有 Bash 脚本的 Shebang 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25165808/

相关文章:

bash - Sed pacman.conf 为 multilib 和 include 删除#

c - 当我尝试追加时,字符串数组被完全重写 - C (xv6)

c++ - 使用 `backticks` 而不是 Pipe | 读取值C++

bash - Shell 是可变数字

linux - 如何检测子目录中的某些文件是否已更改?

linux - linux下如何使用 `find`命令删除非空目录?

在 Bitbucket 中使用预接收 Hook 时无法访问 Git 对象

linux - 带有最后一个退出代码的 Bash 提示

shell - 通过 SSH 执行脚本并获取输出?

bash - 使用 cat 命令输出中的每一行作为文件(ls -l file)