基于 shell 的“开关”

基于 shell 的“开关”

我想来源(即不称呼)来自任何 shell 的脚本(bash/csh 是主要目标,但 Fish、zsh、ksh 和 rc 也很有趣)。

我希望脚本是否可以是单个文件 - 即不是每个 shell 方言的文件。

我可以这样做吗?

我正在考虑类似的事情:

  if shell is bash then
    # bash code here
  else
    if shell is csh then
      # csh code here
    else
      if shell is xxxsh then
        # xxxsh code here
      fi
    endif
  fi

所以我可以这样做:

csh% source my_script
bash$ . my_script

问题是 - 当然,if每种方言都不相同,所以我需要使用对每个 shell 都有效的语法。

编辑

检测外壳是第一步在运行时确定脚本中的 shell做得很好。

同样重要的一步是如何引用 shell 不同部分的代码,以免混淆其他 shell。想一想:如何在 bash 部分中包含<<here_document在 bash 中合法但在任何其他 shell 中非法的所有组合中的所有字符,而不会使其他 shell 感到困惑。任何答案/链接答案均未涵盖这一点。

答案1

您不应该为每个 shell 编写代码片段,而应该只编写可被大多数 shell 解释的可移植代码。你应该看看POSIX Shell 命令语言。这是 shell(遵循 POSIX)应如何解释代码的标准。

许多 shell(例如bash)可以配置为像 POSIX shell 一样运行。每个 shell 都有其独特的功能和特定的符号。在可移植脚本中完全避免使用它们。

答案2

对于类似 csh 和类似 Bourne 的情况,你可以这样做:

start=:#||:<<"goto end="

echo "(t)csh code here"
if { bindkey >& /dev/null } then
  echo tcsh
endif

goto end=

echo Bourne-like code here
if [ -n "$BASH_VERSION" ]; then
  echo bash
fi

end=:

解释:

  • start=:将被视为 中的标签声明csh和 中的变量赋值sh,因此是两个无害的操作。
  • 在 中start=:#,它#被视为评论领导者csh,但在 中则不然,sh因为它不是一个单独的标记。所以后面的内容被注释掉了,csh但没有被注释掉sh
  • 变量赋值sh具有成功退出状态(只要赋值不涉及命令替换),因此||不会运行操作员的命令权限。
  • :<<"goto end="...goto end命令不会运行,但会被解析和忽略("goto end"引用的事实阻止了此处文档内的各种扩展)。但请注意:在 Bourne shell 中(并且仅在 Bourne shell 中),仍然会创建一个临时文件。
  • 因此整个部分直到goto end=被类似 Bourne 的 shell 忽略并由csh.goto end=导致csh忽略 和 之间的部分end=:(类似 Bourne 的 shell 中无害的变量赋值)。

添加的 shell 支持越多,它就越棘手。fish特别是,它非常棘手,因为它会检查整个脚本的语法,即使它不运行的部分也是如此。

也可以看看:

答案3

我认为您想要这样做的原因是为了可移植性。上面的回答给你提供了线索。如果您假设 Bourne shell (sh) 是最小公分母,并且“随处可用”(Linux、Solaris、Unix、AIX 等),那么您可以#!/bin/sh在脚本开头添加 ,并编写所有脚本仅使用 sh 的功能。 (我认为在 Linux 中,sh 只是 bash 的别名,因为 bash 是 Bourne shell 的超集,但不管怎样,它应该仍然可以工作。)

稍微改进一下,假设它sh始终存在,但您可能需要一些更高级 shell 的额外功能和便利性。因此,您可以为您支持的每个 shell 编写一个版本的脚本,例如 script.bash、script.zsh、script.ksh、script.csh 等。每个脚本都以自己的 shebang 行开头,然后在脚本中。 sh 文件你会说这样的话:

#!/bin/sh
if [[ -e /bin/ksh ]] ; then 
 ./script.ksh
 exit
elif [[ -e /bin/csh ]] ; then
 ./script.csh
 exit
fi

ETC。

进一步的建议是研究auto-tools工具链的源代码。当你执行 ./configure 时运行的那些东西;制作 ;进行安装。 GNU 人员做了很多聪明的事情来确保他们的脚本可以在所有环境中运行。

相关内容