条件表达式如何比较字符串?

时间:2013-07-30 09:21:24

标签: bash

#!/usr/bin/env bash
echo 'Using conditional expression:'
[[ ' ' < '0' ]] && echo ok || echo not ok
[[ ' a' < '0a' ]] && echo ok || echo not ok
echo 'Using test:'
[ ' ' \< '0' ] && echo ok || echo not ok
[ ' a' \< '0a' ] && echo ok || echo not ok

输出结果为:

Using conditional expression:
ok
not ok
Using test:
ok
ok

bash --versionGNU bash, version 4.2.45(1)-release (x86_64-pc-linux-gnu)

uname -aLinux linuxmint 3.8.0-19-generic

3 个答案:

答案 0 :(得分:5)

Bash手册说:

  

与[[,&lt;和&gt;运算符使用当前语言环境按字典顺序排序。测试命令使用ASCII排序进行排序。

这归结为分别使用strcoll(3)或strcmp(3)。

使用以下程序(strcoll_strcmp.c)对此进行测试:

#include <stdio.h>
#include <string.h>
#include <locale.h>

int main(int argc, char **argv)
{
    setlocale(LC_ALL, "");

    if (argc != 3) {
        fprintf(stderr, "Usage: %s str1 str2\n", argv[0]);
        return 1;
    }

    printf("strcoll('%s', '%s'): %d\n",
           argv[1], argv[2], strcoll(argv[1], argv[2]));
    printf("strcmp('%s', '%s'): %d\n",
           argv[1], argv[2], strcmp(argv[1], argv[2]));

    return 0;
}

注意区别:

$ LC_ALL=C ./strcoll_strcmp ' a' '0a'
strcoll(' a', '0a'): -16
strcmp(' a', '0a'): -16

$ LC_ALL=en_US.UTF-8 ./strcoll_strcmp ' a' '0a'
strcoll(' a', '0a'): 10
strcmp(' a', '0a'): -16

究竟为什么这些比较如此我不确定。这必须归功于一些英语词典排序规则。我认为确切的规则在ISO 14651 Method for comparing character strings and description of the common template tailorable ordering和随附的模板表中有所描述。 Glibc在libc/localedata/locales下的源代码树中包含此数据。

答案 1 :(得分:4)

您正在观察的行为可以通过以下manual

解释
bash-4.1 and later use the current locale’s collation sequence and strcoll(3).

您似乎正在寻找基于ASCII排序规则的比较。您可以通过设置compat32compat40来更改行为。

$ cat test
shopt -s compat40
echo 'Using conditional expression:'
[[ ' ' < '0' ]] && echo ok || echo not ok
[[ ' a' < '0a' ]] && echo ok || echo not ok
echo 'Using test:'
[ ' ' \< '0' ] && echo ok || echo not ok
[ ' a' \< '0a' ] && echo ok || echo not ok
$ bash test
Using conditional expression:
ok
ok
Using test:
ok
ok

从手册:

compat32
If set, Bash changes its behavior to that of version 3.2 with respect to locale-specific string comparison when using the ‘[[’ conditional command’s ‘<’ and ‘>’ operators. Bash versions prior to bash-4.0 use ASCII collation and strcmp(3); bash-4.1 and later use the current locale’s collation sequence and strcoll(3). 
compat40
If set, Bash changes its behavior to that of version 4.0 with respect to locale-specific string comparison when using the ‘[[’ conditional command’s ‘<’ and ‘>’ operators (see previous item) and the effect of interrupting a command list. 

答案 2 :(得分:2)

<运算符在[ ][[ ]]内使用时,会根据ASCII字母顺序比较两个字符串。这意味着a小于b。这里需要注意的是,因为[ ]有点困难和晦涩,你需要逃避<,其他明智的基础认为你想要重定向。

然而,这两项测试是等价的:

[ 'a' \< 'b' ] && echo ok
[[ 'a' < 'b' ]] && echo ok

在您的示例中,' a'肯定小于'0a',因为空格的小数值为20,而“0”的值为48。

所以我认为你在那里发现了一个错误。

[ ' a' \< '0a' ]

[[ ' a' < '0a' ]]

应该是等效的,[ ]中的那个是正确的。