推荐什么POSIX sh shebang

What is the recommended POSIX sh shebang

我读到,如果您想以便携方式使用 Bash,您应该使用 shebang:

#!/usr/bin/env bash

但现在我想知道:当我想明确声明我不依赖 Bash,而是写了一个 POSIX 兼容的脚本时,我应该使用:

#!/bin/sh

或者 #!/usr/bin/env sh 在这里也更可取吗?

正式视角

POSIX 规范的信息部分 sh:应用程序使用 状态 您不能依赖安装在 /bin/sh.

sh 可执行文件

Applications should note that the standard PATH to the shell cannot be assumed to be either /bin/sh or /usr/bin/sh, and should be determined by interrogation of the PATH returned by getconf PATH, ensuring that the returned pathname is an absolute pathname and not a shell built-in.

For example, to determine the location of the standard sh utility:

command -v sh

但是,不是建议使用 env 来使用适当的 PATH, 它建议 shell 脚本应该在安装时修改以使用 sh:

的完整路径

Furthermore, on systems that support executable scripts (the "#!" construct), it is recommended that applications using executable scripts install them using getconf PATH to determine the shell pathname and update the "#!" script appropriately as it is being installed (for example, with sed).

在实践中

我主要编写 POSIX shell 脚本,实际上,每个 GNU/Linux 系统 (基于 Red Hat 和 Debian)——以及其他如 Cygwin 和 OS X——有一个 POSIX 兼容 sh 安装到 /bin/sh 或作为软件或 在这条路上很难link。我从来不需要使用 env 来迎合系统 其中 sh 不使用此路径。

可能有一些 Unix 系统的 POSIX 兼容 sh 不可用 作为 /bin/sh。 POSIX 规范表明它可能安装在 一些系统为 /usr/xpg4/bin/sh。据我了解,这是(曾经?)真实的 对于 Solaris 系统,其中 /bin/sh 是 Bourne shell 的早期版本 它早于 POSIX。在这种情况下,使用 env sh 不能保证有帮助,因为它仍然可以在 POSIX shell 之前找到 Bourne shell(在 /bin/sh)在 /usr/xpg4/bin/sh.

总结

如果您正在为通用 Unix 和 Linux 操作系统编写 POSIX shell 脚本 系统,只需使用 #!/bin/sh 作为 shebang。

在极少数情况下 /bin/sh 是 Bourne shell 而不是 POSIX 兼容 shell,您必须修改 shebang 才能使用适当的完整路径 到 POSIX shell.

在任何一种情况下,使用 #!/usr/bin/env sh 都没有任何好处——而且会 比简单地使用 #!/bin/sh.

更容易失败

我会说 #!/usr/bin/env sh 更可取。

一些可移植的结构,例如the loop over the results of find,需要显式调用 sh。考虑这个脚本:

#!/bin/sh
# ... some commands here ...
find . -exec sh -c '
  for file do
    # ... commands processing "$file" ...
  done' find-sh {} +

开头的命令将由 /bin/sh 变为 运行,而处理 "$file" 的命令将由最先出现的 sh 变为 运行在 PATH 中,其行为可能与 /bin/sh 不同。这是意外错误的潜在来源。 #!/usr/bin/env sh shebang 解决了这个问题,因为所有命令都将由您的 PATH 中第一个 sh 运行。

#!/usr/bin/env sh shebang 的唯一潜在缺点是 /usr 可能不会在调用脚本时挂载。但是,这在实践中不应该经常发生。可移植脚本中经常使用的外部程序,例如 awk,也经常在 /usr/bin 中找到,因此可能很难确保脚本 运行s 与 /usr 正确反正卸载了。

如果你真的想要便携并且不依赖于 /usr 被安装,你可以开始你的脚本如下,以确保它总是由 sh 从 PATH 执行,无论在哪里它是:

#!/bin/sh
if test X"$SUBSHELL" != X"1"; then
  SUBSHELL=1
  export SUBSHELL
  exec sh "[=11=]" "$@"
  exit 1
fi

# ... your actual script comes here ...

但这似乎有点矫枉过正,所以我认为 #!/usr/bin/env sh shebang 是一个合理的妥协。