我一直在用shell脚本来自动化一些任务。什么是最好的方法来确保shell脚本在大多数平台上运行没有任何问题。例如,我一直在使用echo -n命令将一些消息打印到屏幕上,没有尾随新行,-n开关在一些ksh shell中不起作用。我被告知脚本必须符合POSIX。我如何确保脚本是POSIX兼容的?有没有工具?或者有没有只支持最低POSIX要求的shell?
echo -n
-n
kuhbmx9i1#
第一步是将shebang设置为/bin/sh和use shellcheck site以分析脚本,这将指示哪些操作有效或无效以及为什么。例如,将以下脚本粘贴到shellcheck编辑器窗口中:
/bin/sh
#!/bin/sh read -r a b <<<"$1" echo $((a+b))
以获得指示:在POSIX sh中,here-string是未定义的。第二步,可以使用尽可能与POSIX兼容的shell。is dash是一个与大多数其他简单shell兼容的shell,它是Debian的默认系统shell,是旧的BSD ash的衍生物。另一个与posix兼容的shell是posh。但是,破折号和/或豪华可能不适用于某些系统。还有lksh(带有ksh的味道),目标是与遗留(旧的)shell脚本兼容。lksh是一个命令解释器,专门用于运行遗留shell脚本。但是在调用lksh时需要使用选项,比如-o posix和-o sh:请注意,强烈建议至少使用-o posix选项调用lksh(如果不是同时使用-o posix选项和-o sh),以充分享受与POSIX标准(这可能是您首先使用lksh而不是mksh的原因)或遗留脚本的更好兼容性。您可以调用lksh -o posix -o sh,而不是简单的lksh。使用选项是使其他shell兼容POSIX的一种方法,比如lksh,使用选项-o posix,比如bash -o posix。在bash中,甚至可以在脚本中调用POSIX选项,方法是:
-o posix
-o sh
lksh -o posix -o sh
lksh
bash -o posix
shopt -o posix # also with: set -o posix
也可以创建一个到bash或zsh的本地链接,使两者都像旧的sh shell一样运行。
bash
zsh
sh
$ ln -s /bin/bash ./sh $ ./sh
有很多替代方法(dash、posh、lksh、bash、zsh等)可以获得一个可以作为POSIX shell工作的shell。
不过,即便如此,以上种种也并不能保证“便携性”。不幸的是,使shell脚本“与POSIX兼容”通常比使其在任何实际shell上运行要容易。现实世界中唯一明智的建议是在多个shell中测试脚本。就像上面的列表:破折号,豪华,lksh,和bash -posix。Solaris是一个独立的世界,您可能需要针对/bin/sh和xpg 4/sh进行测试。随访:How can I test for POSIX compliance for shell scripts?
sbtkgmzw2#
使用--posix命令行选项启动Bash或在Bash运行时执行'set -o posix'将使Bash更接近POSIX标准,方法是在Bash默认值不同的区域更改行为以匹配POSIX指定的行为。Reference
bqf10yzr3#
注:
dash
对于proof-of-the-pudding-is-in-the-eating方法,可以考虑使用shall(我编写的一个实用程序),它允许您一次使用 * 多个 * shell调用给定的脚本或命令,并提供关于使用哪个目标shell成功执行脚本/命令的反馈。如果你已经安装了Node.js,你可以很容易地用npm install -g shall来安装它(如果没有,请点击上面的链接到GitHub repo获取手动安装说明),然后按如下方式使用它:
shall
npm install -g shall
shall scriptFile
或者,使用特定命令:
shall -c '<shell-commands>'
默认情况下,它调用sh,如果安装了dash、bash、zsh和ksh,但是**您可以通过使用SHELLS环境变量将已安装的任何一组shell作为目标。以macOS上的echo -n命令为例,仅将shell sh和bash作为目标:
ksh
SHELLS
$ SHELLS=sh,bash shall -c 'echo -n hi' ✓ sh (bash variant) [0.00s] -n hi ✓ bash [0.00s] hi OK - All 2 shells (sh, bash) report success.
在macOS上,bash(有效地)充当sh,而echo -n在与sh一起使用时没有"失败",您还可以看到,当bash作为sh运行时,-n没有被识别为"选项"。另一个macOS示例显示bash允许某些特定于Bash的扩展,即使在以sh运行时也是如此,例如使用非标准的[[ ... ]]条件(假设dash-在Ubuntu系统上充当sh-是通过Homebrew安装的):
[[ ... ]]
$ SHELLS=sh,bash,dash shall -c '[[ -n nonempty ]] && echo nonempty' ✓ sh (bash variant) [0.00s] nonempty ✓ bash [0.00s] nonempty ✗ dash [0.01s] dash: 1: [[: not found FAILED - 1 shell (dash) reports failure, 2 (sh, bash) report success.
正如您所看到的,以sh运行的Bash仍然接受[[ ... ]],而dash(主要是)仅支持POSIX特性的shell,* 失败 *,因为POSIX只要求[ ... ]条件(作为test ...命令的别名)。
[ ... ]
test ...
3条答案
按热度按时间kuhbmx9i1#
POSIX
第一步是将shebang设置为
/bin/sh
和use shellcheck site以分析脚本,这将指示哪些操作有效或无效以及为什么。例如,将以下脚本粘贴到shellcheck编辑器窗口中:
以获得指示:在POSIX sh中,here-string是未定义的。
第二步,可以使用尽可能与POSIX兼容的shell。
is dash是一个与大多数其他简单shell兼容的shell,它是Debian的默认系统shell,是旧的BSD ash的衍生物。
另一个与posix兼容的shell是posh。
但是,破折号和/或豪华可能不适用于某些系统。
还有lksh(带有ksh的味道),目标是与遗留(旧的)shell脚本兼容。
lksh是一个命令解释器,专门用于运行遗留shell脚本。
但是在调用lksh时需要使用选项,比如
-o posix
和-o sh
:请注意,强烈建议至少使用-o posix选项调用lksh(如果不是同时使用-o posix选项和-o sh),以充分享受与POSIX标准(这可能是您首先使用lksh而不是mksh的原因)或遗留脚本的更好兼容性。
您可以调用
lksh -o posix -o sh
,而不是简单的lksh
。使用选项是使其他shell兼容POSIX的一种方法,比如lksh,使用选项
-o posix
,比如bash -o posix
。在bash中,甚至可以在脚本中调用POSIX选项,方法是:
也可以创建一个到
bash
或zsh
的本地链接,使两者都像旧的sh
shell一样运行。有很多替代方法(dash、posh、lksh、bash、zsh等)可以获得一个可以作为POSIX shell工作的shell。
便携式
不过,即便如此,以上种种也并不能保证“便携性”。
不幸的是,使shell脚本“与POSIX兼容”通常比使其在任何实际shell上运行要容易。
现实世界中唯一明智的建议是在多个shell中测试脚本。
就像上面的列表:破折号,豪华,lksh,和bash -posix。
Solaris是一个独立的世界,您可能需要针对/bin/sh和xpg 4/sh进行测试。
随访:
How can I test for POSIX compliance for shell scripts?
sbtkgmzw2#
使用--posix命令行选项启动Bash或在Bash运行时执行'set -o posix'将使Bash更接近POSIX标准,方法是在Bash默认值不同的区域更改行为以匹配POSIX指定的行为。
Reference
bqf10yzr3#
注:
/bin/sh
。/bin/sh
,系统默认shell,不应该被认为支持除POSIX规定的特性之外的任何特性,尽管在实践中它在不同程度上支持,这取决于具体的实现。因此,在一个平台上成功地通过/bin/sh
运行并不 * 保证脚本在另一个平台上也能工作。在广泛使用的shell中,dash
最接近于仅包含POSIX特性的shell。对于proof-of-the-pudding-is-in-the-eating方法,可以考虑使用
shall
(我编写的一个实用程序),它允许您一次使用 * 多个 * shell调用给定的脚本或命令,并提供关于使用哪个目标shell成功执行脚本/命令的反馈。如果你已经安装了Node.js,你可以很容易地用
npm install -g shall
来安装它(如果没有,请点击上面的链接到GitHub repo获取手动安装说明),然后按如下方式使用它:或者,使用特定命令:
默认情况下,它调用
sh
,如果安装了dash
、bash
、zsh
和ksh
,但是**您可以通过使用SHELLS
环境变量将已安装的任何一组shell作为目标。以macOS上的
echo -n
命令为例,仅将shellsh
和bash
作为目标:在macOS上,
bash
(有效地)充当sh
,而echo -n
在与sh
一起使用时没有"失败",您还可以看到,当bash
作为sh
运行时,-n
没有被识别为"选项"。另一个macOS示例显示
bash
允许某些特定于Bash的扩展,即使在以sh
运行时也是如此,例如使用非标准的[[ ... ]]
条件(假设dash
-在Ubuntu系统上充当sh
-是通过Homebrew安装的):正如您所看到的,以
sh
运行的Bash仍然接受[[ ... ]]
,而dash
(主要是)仅支持POSIX特性的shell,* 失败 *,因为POSIX只要求[ ... ]
条件(作为test ...
命令的别名)。