2013-07-30 10 views
7
#!/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 

Wyjście jest:W jaki sposób wyrażenie warunkowe porównuje łańcuchy?

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

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

uname -a: Linux linuxmint 3.8.0-19-generic

Odpowiedz

5

Bash instrukcja mówi:

przypadku korzystania z [[The < i> operatorzy tak rt leksykograficznie za pomocą bieżącego locale. Polecenie testowe sortuje przy użyciu uporządkowania ASCII.

Sprowadza się to do używania odpowiednio strcoll (3) lub strcmp (3).

Użyj następującego programu (strcoll_strcmp.c), aby przetestować to:

#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; 
} 

zauważyć różnicę:

$ 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 

dokładnie, dlaczego to porównanie jako taki nie jestem pewien. Musi to być spowodowane niektórymi angielskimi zasadami sortowania leksykograficznego. Myślę, że dokładne zasady są opisane w ISO 14651 Method for comparing character strings and description of the common template tailorable ordering i dołączonej tabeli szablonów. Glibc zawiera te dane w drzewie źródłowym pod numerem libc/localedata/locales.

+0

Ale dlaczego jedna przestrzeń jest mniejsza niż 'a' w obu przypadkach? – updogliu

+0

@updogliu Zobacz dodatek na dole mojej odpowiedzi. – spbnick

+0

Próbowałem kilku przypadków. Wygląda na to, że wiodące białe spacje są po prostu odrzucane w 'strcoll'. – updogliu

2

Operator < używany wewnątrz [ ] lub [[ ]] porównuje dwa ciągi zgodnie z kolejnością alfabetyczną ASCII. Oznacza to, że a jest mniejszy niż b. Zastrzeżenie tutaj jest takie, że ponieważ [ ] jest nieco trudny i tajemniczy, musisz uciec <, inna mądra baza myśli, że chcesz przekierować.

Oba badania są jednak equvivalent:

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

W przykładzie ' a' jest zdecydowanie mniej niż '0a', jako przestrzeń ma wartość dziesiętną 20, a '0' ma wartość 48.

Tak Myślę, że znalazłeś tam błąd.

[ ' a' \< '0a' ] 

i

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

powinny być równe, zaś jedna [ ] jest poprawne.

4

Zachowanie że jesteś obserwacji można wyjaśnić następujące od manual przez:

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

Wydaje się, że szuka dla porównania na podstawie sortowania ASCII. Możesz zmienić zachowanie, ustawiając compat32 lub compat40.

$ 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 

Z instrukcji:

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. 
Powiązane problemy