【问题标题】:What is the recommended POSIX sh shebang什么是推荐的 POSIX sh shebang
【发布时间】:2019-04-06 13:26:00
【问题描述】:

我已经读过,如果你想以便携的方式使用 Bash,你应该使用 shebang:

#!/usr/bin/env bash

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

#!/bin/sh

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

【问题讨论】:

  • #!/usr/bin/env sh 不是适得其反吗?如果/usr 在单独的分区上,即使/usr 没有挂载,#!/bin/sh 的脚本也可以使用,而#!/usr/bin/env sh 会失败,即使sh 在/bin 中也是如此。我同意这种情况很少见,但仍然如此。
  • 确实,对于默认 shell(如 sh)可能有问题,但对于其他 shell(如 bash),它似乎是 necessary。
  • 即使使用bash,它也扩展了便携的定义。它所说的只是“使用任何名为bash 的程序首先出现在您的路径中”。它没有说明bash 的版本应该是什么(3.2?4.0?4.1?4.2?4.3?4.4?5.0?),甚至没有说名为bash 的程序甚至是 重击。记录运行脚本所需的内容;让用户担心如何指定。

标签: shell sh posix


【解决方案1】:

我会说#!/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" 的命令将由PATH 中最先出现的sh 运行,其行为可能与/bin/sh 不同。这是意外错误的潜在来源。 #!/usr/bin/env sh shebang 解决了这个问题,因为所有命令都将由 PATH 中的第一个 sh 运行。

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

如果您真的想要便携而不依赖于安装的/usr,您可以按如下方式开始您的脚本,以确保它始终由PATH 中的sh 执行,无论它在哪里:

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

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

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

【讨论】:

    【解决方案2】:

    形式观点

    POSIX specification for sh: Application Usage 状态的信息部分 你不能依赖安装在/bin/sh 的sh 可执行文件。

    应用程序应注意,shell 的标准 PATH 不能 假定为 /bin/sh 或 /usr/bin/sh, 并且应该是 通过查询返回的 PATH 确定 getconf PATH,确保返回的路径名是绝对路径名而不是 内置的外壳。

    例如,要确定标准 sh 实用程序的位置:

    command -v sh
    

    但是,与其建议使用env 来使用适当的PATH, 它建议应在安装时修改 shell 脚本以使用 sh 的完整路径:

    此外,在支持可执行脚本(“#!” 构造),建议使用可执行脚本的应用程序 使用安装它们 getconf PATH 确定 shell 路径名并更新“#!”脚本 在安装时适当地安装(例如,使用 sed)。

    在实践中

    我主要编写 POSIX shell 脚本,实际上,每个 GNU/Linux 系统 (基于 Red Hat 和 Debian)——以及 Cygwin 和 OS X 等其他软件——具有 符合 POSIX 标准的 sh 可以安装到 /bin/sh 或作为软件或 此路径上的硬链接。我从来不需要使用env 来满足系统需求 其中sh 不使用此路径。

    可能有一些 Unix 系统无法使用符合 POSIX 标准的sh 作为/bin/sh。 POSIX 规范建议它可能安装在 一些系统为/usr/xpg4/bin/sh。据我了解,这是(是?)真的 对于 /bin/sh 是 Bourne shell 的早期版本的 Solaris 系统 它早于 POSIX。在这种情况下,不能保证使用env sh 会有所帮助,因为它仍然可以在/usr/xpg4/bin/sh 的POSIX shell 之前找到Bourne shell(/bin/sh)。

    总结

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

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

    在任何一种情况下,使用 #!/usr/bin/env sh 都没有任何好处——而且会是 比简单地使用#!/bin/sh更有可能失败。

    【讨论】:

    • 好的,所以您的建议是尽可能使用安装工具(例如,configure、make),否则坚持使用#!/bin/sh?
    • @JepZ 我已经更新了我的答案。我希望现在更清楚了。
    • 在 Solaris 上想要 POSIX 语义的人不会只是确保/usr/xpg4/bin 在他们的PATH 中出现在/usr 之前吗?
    • @tripleee 好点。我从来没有亲自使用过 Solaris(只有 GNU/Linux、Cygwin 和 OS X)——但如果我必须这样做,我会这样做。
    • @JepZ 这就是我的建议。从开发者那里,shebang 是一个推荐; 安装程序知道正确的解释器在本地系统中的位置。
    猜你喜欢
    • 2013-05-24
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多