这让我措手不及!
我们有一台 Solaris 机器(版本:SunOS 5.8),托管一个关键脚本/进程,该脚本/进程已经运行了很多年,没有任何投诉。我们最近有理由深入了解一下,发现一个测试条件——据我所知——不应该起作用,但由于某种原因可以:
$ sh
$ [ 90% -gt 95 ]; echo $?
1
$ [ 96% -gt 95 ]; echo $?
0
什么?!这看起来并不是侥幸:
$ [ 96% -lt 95 ]; echo $?
1
$ [ 96% -eq 96 ]; echo $?
0
这不仅仅是以下%
两者之一:
$ [ 96blah -eq 96 ]; echo $?
0
$ [ 1.2 -gt 1 ]; echo $?
1
在 SunOS 5.8、5.9 和 5.10 上似乎是这样,但我以前没有注意到这一点。不幸的是,我手边似乎没有另一个非 Solaris 系统可以轻松地检查它是否没有/bin/sh
符号链接到 bash(它的解释不太自由)。
那么,除了草率的代码(x%
通过变量传递并且可能没有被注意到)之外,为什么标准(大概是 Bourne?)shell 通过截断这些测试参数将它们视为整数?这是有记录的行为吗?我看不到任何东西,man sh
但可能错过了一些东西。
注意:这实际上是另一个奇怪的测试条件下的次要嘘声,但这可能值得它自己的问题。
答案1
由于我无法将注释格式化为预期的行,因此我使用答案表单来解释有关如何获取 POSIX shell 的注释。
获取 POSIX shell 的官方方法是:
1) unset PATH # if you run an older Bourne Shell
2a) PATH=`getconf PATH` # this is with the Bourne Shell
2b) PATH=$(command -p getconf PATH) # this is with a Korn shell
3) sh # This starts a POSIX shell
已经进行了多次标准化尝试#!/path/to/shell
,但 POSIX 不处理 PATH,因此我们找不到解决方案。
答案2
看起来这个问题已经在评论中得到了回答:Solarissh
有一些怪癖。至少在过去,它甚至不是 POSIX shell。 (Schily 指出 POSIX 不需要/bin/sh
是 POSIX sh
,这意味着您必须跳过另一个环节才能编写完全可移植的 shell 脚本。)
这个问题可能有一些有用的信息/链接:https://superuser.com/questions/125728/what-is-the-difference- Between-bash-and-sh
Schily 的回答指出,该标准没有指定尾随垃圾的数字会发生什么,因此您的脚本实际上具有未定义的行为,并且依赖于 Solaris 的行为sh
。因此,它不可移植。
bash
类似的事情是显然不建议在/bin/sh
Solaris 系统上使用它的主要原因。一些 GNU/Linux 发行版使用dash
for /bin/sh
,而其他发行版则使用bash
.
我在我安装的 3 个 shell 上测试了你的代码:
bash 4.3-11ubuntu2
$ [ 96blah -eq 96 ]; echo $?
bash: [: 96blah: integer expression expected
2
dash 0.5.7-4ubuntu1
$ [ 96blah -eq 96 ]; echo $?
dash: 1: [: Illegal number: 96blah
2
busybox sh 1.22.0-9ubuntu1
$ [ 96blah -eq 96 ]; echo $?
sh: 96blah: bad number
2
答案3
该标准规定测试运算符喜欢-gt
将其操作数作为整数进行比较,但它没有提到当提供的字符串不是整数时会发生什么。所以观察到的行为是完全正确的。顺便说一句:它也与历史 UNIX 行为兼容。
/bin/sh 当然没有链接到 bash,因为 bash 不够符合标准,可能会导致很多脚本失败。
2010 年,随着 Solaris 10 的发展,/bin/sh 被 ksh93 取代,尽管 ksh 比 bash 更兼容 Bourne Shell,但这导致 Solaris 无法在不同的文件系统中拥有 / 和 /usr之前没有问题。请注意,ksh93 从 /usr 加载动态库。