Gor*_*son 67
shell 脚本大约有四个级别的可移植性(就 shebang 行而言):
最便携:使用#!/bin/shshebang 并仅使用POSIX 标准中指定的基本 shell 语法。这应该适用于几乎所有 POSIX/unix/linux 系统。(好吧,除了 Solaris 10 及更早版本,它们具有真正的传统 Bourne shell,早于 POSIX,因此不符合,如/bin/sh.)
第二个最便携:使用#!/bin/bash(或#!/usr/bin/env bash)shebang 行,并坚持使用 bash v3 功能。这适用于任何具有 bash 的系统(在预期位置)。
第三个最便携:使用#!/bin/bash(或#!/usr/bin/env bash)shebang 行,并使用 bash v4 功能。这将在任何具有 bash v3 的系统上失败(例如 macOS,出于许可原因必须使用它)。
最不便携:使用#!/bin/shshebang 并使用 bash 对 POSIX shell 语法的扩展。这将在任何系统上失败,因为 /bin/sh 具有除 bash 之外的其他内容(例如最近的 Ubuntu 版本)。永远不要这样做;这不仅仅是一个兼容性问题,这完全是错误的。不幸的是,这是很多人都会犯的错误。
我的建议:使用提供脚本所需的所有 shell 功能的前三个中最保守的一个。为了最大的可移植性,请使用选项 #1,但根据我的经验,一些 bash 功能(如数组)非常有用,我将使用 #2。
你能做的最糟糕的事情是#4,使用错误的shebang。如果您不确定哪些功能是基本的 POSIX,哪些是 bash 扩展,要么坚持使用 bash shebang(即选项 #2),要么使用非常基本的 shell(如 Ubuntu LTS 服务器上的 dash)彻底测试脚本。Ubuntu wiki 有一个很好的 bashisms 列表需要注意。
在 Unix 和 Linux 问题“与 sh 兼容是什么意思?”中,有一些关于 shell 之间的历史和差异的非常好的信息。和 Stackoverflow 问题“sh 和 bash 之间的区别”。
另外,请注意 shell 并不是不同系统之间唯一不同的东西;如果你习惯了 linux,你就会习惯 GNU 命令,它有很多非标准的扩展,你可能在其他 unix 系统(例如 bsd、macOS)上找不到。不幸的是,这里没有简单的规则,您只需要知道您使用的命令的变化范围。
就可移植性而言,最讨厌的命令之一是最基本的命令之一:echo. 任何时候您将它与任何选项(例如echo -n或echo -e)或字符串中的任何转义(反斜杠)一起使用以进行打印,不同的版本会做不同的事情。任何时候你想打印一个没有换行符的字符串,或者字符串中有转义符,请printf改用(并了解它是如何工作的——它比echo现在更复杂)。该ps命令还很乱。
另一个需要注意的一般事项是最近/GNUish 对命令选项语法的扩展:旧(标准)命令格式是命令后跟选项(带有一个短划线,每个选项都是一个字母),然后是命令参数。最近的(通常是不可移植的)变体包括长选项(通常用 引入--),允许选项在参数之后,并--用于将选项与参数分开。
在./configure为构建 TXR 语言准备的脚本中,为了更好的可移植性,我编写了以下序言。即使#!/bin/sh是不符合 POSIX 的旧 Bourne Shell,该脚本也会自行引导。(我在 Solaris 10 VM 上构建每个版本)。
#!/bin/sh
# use your own variable name instead of txr_shell;
# adjust to taste: search for your favorite shells
if test x$txr_shell = x ; then
for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
if test -x $shell ; then
txr_shell=$shell
break
fi
done
if test x$txr_shell = x ; then
echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
txr_shell=/bin/sh
fi
export txr_shell
exec $txr_shell $0 ${@+"$@"}
fi
# rest of the script here, executing in upgraded shell
Run Code Online (Sandbox Code Playgroud)
这里的想法是我们找到一个比我们正在运行的 shell 更好的 shell,并使用该 shell 重新执行脚本。在txr_shell环境变量设置,使重新执行脚本知道它是重新执行递归实例。
(在我的脚本中,该txr_shell变量也随后被使用,正好有两个目的:首先,它作为脚本输出中信息性消息的一部分被打印出来。其次,它被安装为 中的SHELL变量Makefile,以便make将使用这个shell 也用于执行配方。)
在/bin/sh破折号的系统上,您可以看到上述逻辑将找到/bin/bash并重新执行脚本。
在 Solaris 10 机器上,/usr/xpg4/bin/sh如果没有找到 Bash ,它将启动。
序言是用保守的 shell 方言编写的,test用于文件存在测试,以及${@+"$@"}扩展参数以迎合一些损坏的旧 shell的技巧("$@"如果我们在符合 POSIX 的 shell 中就简单了)。
| 归档时间: |
|
| 查看次数: |
6004 次 |
| 最近记录: |