Bash字符串比较

7
我正在尝试在Bash脚本中比较两个字符串,但是结果非常奇怪。
if [[ "010" < "01." ]]; then echo "Wrong"; else echo "OK"; fi
if [[ "010" < "01.0" ]]; then echo "Wrong"; else echo "OK"; fi
if [ "010" \< "01." ]; then echo "Wrong"; else echo "OK"; fi
if [ "010" \< "01.0" ]; then echo "Wrong"; else echo "OK"; fi

阅读文档后,我发现 [[ < ]][ \< ] 看起来应该是一样的,但实际上并不是。当字符串长度不相同时,[[ < ]] 的工作方式似乎是错误的。请问我有什么遗漏吗?
期望的结果是 4 x OK。测试环境如下:
- CentOS release 6.4 (Final) - GNU Bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) (OK Wrong OK OK) - Ubuntu 14.04.2 (Trusty Tahr) LTS - GNU Bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) (OK Wrong OK OK) - openSUSE 13.1 (Bottle) (x86_64) - GNU Bash, version 4.2.53(1)-release (x86_64-suse-linux-gnu) (OK OK OK OK)

3
请添加脚本的输出结果。 - moffeltje
我确认出现了奇怪的行为:输出显示为“OK,wrong,OK,OK”;而对我来说预期的输出应该是“OK,wrong,OK,wrong”,因为在我的电脑上这些值被排序为“01.”,“010”,“01.0”。 - Chris Maes
请注意,奇怪的行为仅在极限情况下进行排序时发生;当使用单括号和双括号时似乎使用了不同的排序算法;这可能吗? - Chris Maes
查看ASCII表,.在0之前,因此字符串的预期顺序应为01.、01.0、010。 - Marin
在我的电脑上(opensuse13.1-32,bash 4.2.53)执行命令 echo -e "01.0\n010\n01." | sort 的输出结果是 "01.", "010", "01.0",而期望的输出结果应该是 "ok, wrong, ok, wrong"。因此,我猜测这种排序差异可能是答案的提示。 - Chris Maes
显示剩余3条评论
3个回答

1
这是help test的文档:

STRING1 > STRING2

如果 STRING1 按字典顺序排在 STRING2 之后,则返回 True。

以第一个 if 语句为例:
if [[ "010" < "01." ]]; then echo "Wrong"; else echo "OK"; fi

在Bash中,字符串"01."按字典顺序排在字符串"010"之前(您可以在其他工具中进行测试,如Microsoft Excel),因此比较返回false。对于您的所有4个比较都是如此。请注意,在"01."末尾添加一个额外的0并不会改变与"010"的排序顺序,因此仍然得到相同的结果。

我使用的是bash 4.2.53 (opensuse13.1); 我得到了"OK, wrong, OK, OK"的结果;所以他说的有道理... - Chris Maes
我也在Bash 4.2.53上,所有4个都得到了OK。这真的很奇怪。 - Tim Biegeleisen
当我对这三个值进行排序时,得到的结果是:"01."、"010"、"01.0"。 - Chris Maes
确实很奇怪。在运行bash 3.2.*的OSX上,我得到了OKOKOKOK。在运行bash 4.1.2的AWS Linux上,我得到了OKWrongOKOK - Darragh Enright
3
你可能会说我在发布这个回答时有些害羞。那么如何解释原始问题呢? - Tim Biegeleisen

0

可能的原因是从Bash 4.1开始,<和>字符串比较运算符会考虑语言环境。

因此,在两个系统之间可能存在以下差异:

  1. 不同的语言环境-通过运行locale来检查(有关不同语言环境设置的含义,请参见“LC_ALL=C”是什么意思?
  2. 即使语言环境相同,shopt compat31或compat32可能已打开(Bash 3.1或3.2兼容模式),这意味着字符串比较将不会考虑语言环境-通过运行shopt来检查

进一步阅读:


-1
如果你想比较整数,你应该这样做:
if [[ 10 < 1 ]]; then echo "10 < 1"; else echo "10 > 1"; fi

# Result:
#
#   10 > 1

如果你想要比较浮点数,可以看看这个帖子:Bash中如何进行浮点数比较? 针对你的例子:
echo "10 < 1.0" | bc
# Return: 0

echo "10 > 1.0" | bc
# Return: 1

我有些困惑地看到这个答案是不正确的。以下是一些命令示例:mat@lapdev001:~$ if [[ 11 < 10 ]]; then echo "<"; else echo ">";fi
mat@lapdev001:$ if [[ 11 < 25 ]]; then echo "<"; else echo ">";fi < 字符串比较如下:mat@lapdev001:$ if [[ "longstring" > "string" ]]; then echo "<"; else echo ">";fi
mat@lapdev001:~$ if [[ "string" > "string" ]]; then echo "<"; else echo ">";fi
mat@lapdev001:~$ if [[ "string" > "longstring" ]]; then echo "<"; else echo ">";fi <
- Mathieu Coavoux
编辑(更改)您的答案以添加额外信息,而不是在评论中添加(但不要包括“编辑:”,“更新:”或类似内容 - 答案应该看起来像是今天写的)。评论可以随时删除。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接