编写可以在任何 shell 上运行的 shell 脚本(使用多个 shebang 行?)

编写可以在任何 shell 上运行的 shell 脚本(使用多个 shebang 行?)

我刚刚开始深入研究 shell 脚本,我总是将脚本放入一个文件中,标记它chmod +x,然后完成/path/to/script.sh,让默认解释器执行它,我假设它是 zsh,因为我的 shell 就是用的这个。显然,/bin/sh即使我从 zsh 提示符执行脚本,它似乎也是默认的,因为我开始在脚本中加入 zsh 特定的内容,除非我运行,否则它会失败zsh /path/to/script.sh

为了切中要点,以下是我的问题:

  1. #!/path/to/shell当开头没有 shebang 行 ( ) 时,哪个 shell 会执行脚本?我假设是/bin/sh这样,但无法确认。
  2. 就编写可在任何平台上运行的 shell 脚本而言,什么被视为“最佳实践”?(好吧,这有点开放式)
  3. 是否可以编写一个脚本,尝试使用 zsh,如果 zsh 不可用则返回到 bash?我尝试过放置两个 shebang 行,如下所示,但bad interpreter: /bin/zsh: no such file or directory如果我在没有 zsh 的机器上尝试,它只会出错。

    #!/bin/zsh

    #!/bin/bash

答案1

当开头没有 shebang 行 (#!/path/to/shell) 时,哪个 shell 会执行脚本?我假设是 /bin/sh,但我无法确认。

内核拒绝执行此类脚本并返回 ENOEXEC,因此具体行为取决于运行此类脚本的程序

  • bash 4.2.39 – 使用自身
  • busybox-ash 1.20.2 – 使用自身
  • dash 0.5.7 – 运行 /bin/sh
  • fish 1.23.1 – 抱怨 ENOEXEC,然后指责错误的文件
  • AT&T ksh 93u+2012.08.01 – 使用自身
  • mksh R40f – 运行 /bin/sh
  • pdksh 5.2.14 – 运行 /bin/sh
  • sh-heirloom 050706 – 自身使用
  • tcsh 6.18.01 – 运行 /bin/sh
  • zsh 5.0.0 – 运行 /bin/sh
  • cmd.exe 5.1.2600 – 看起来很有趣。

glibc、函数execv()execve()仅返回 ENOEXEC。但execvp()会隐藏此错误代码并自动调用 /bin/sh。(这在执行(3p)

就编写可在任何平台上运行的 shell 脚本而言,什么被视为“最佳实践”?(好吧,这有点开放式)

要么坚持sh使用 POSIX 定义的特性,要么就完全狂欢(广泛可用)并在分发时在您的要求中提及它。

(现在我想起来,Perl——或者可能是 Python——的可移植性会更强,更不用说具有更好的语法了。)

总是添加 shebang 行。如果使用 bash 或 zsh,请使用#!/usr/bin/env bash而不是硬编码 shell 的路径。(但是,POSIX shell 保证位于/bin/sh,因此在这种情况下跳过env。)

(不幸的是,即使/bin/sh并不总是相同的。GNU自动配置程序必须处理许多不同的怪癖

是否可以编写一个脚本,尝试使用 zsh,如果 zsh 不可用,则返回到 bash?我尝试过输入两行 shebang,如下所示,但它只是出错了错误的解释器:/bin/zsh:没有此文件或目录如果我在没有 zsh 的机器上尝试它。

只能有一个 shebang 行;换行符后的所有内容都不会被内核读取,并且会被 shell 视为注释。

它是可能的编写一个脚本,以 运行#!/bin/sh,检查哪个 shell 可用,并根据结果运行exec zsh "$0" "$@"或。但是,bash 和 zsh 使用的语法在各个地方有很大不同,因此我会exec bash "$0" "$@"不建议这样做为了您自己的理智。

答案2

1) 你当前正在运行的 shell。(无论是什么 shell)

2) 坚持使用相同的 shell 类型(bash/dash/ash/csh/无论你喜欢哪种类型),并确保你的“支持平台”默认安装你希望使用的 shell。此外,尽量使用系统上常用的命令。避免使用特定于机器的选项。

3) 实际上没有“if-then-else”逻辑interpreter directive。您应该指定一个存在于您希望支持的所有系统上的 shell... 即,只要您的脚本在所有 shell 中都相当通用,#!/bin/bash就可以指定一个通用的 shell 。#!/bin/sh

相关内容