bash: zepsułem [[<]]

14

Pisałem skrypt bash i nagle takie zachowanie się zaczęło:

[[ 1 < 2 ]]; echo $?  # outputs 0
[[ 2 < 13 ]]; echo $? # outputs 1

ale -ltdziała solidnie:

[[ 1 -lt 2 ]]; echo $?  # outputs 0
[[ 2 -lt 13 ]]; echo $? # outputs 0

czy <jakoś przypadkowo nadpisałem ?

oto skrypt, który napisałem, aby przetestować to zachowanie:

#!/bin/bash

for a in {1..5}
do
    for b in {1..20}
    do
        [[ $a < $b ]] && echo $a $b
    done

    echo
done

oto wynik:

1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
1 11
1 12
1 13
1 14
1 15
1 16
1 17
1 18
1 19
1 20

2 3
2 4
2 5
2 6
2 7
2 8
2 9
2 20

3 4
3 5
3 6
3 7
3 8
3 9

4 5
4 6
4 7
4 8
4 9

5 6
5 7
5 8
5 9

zmiana <na -ltw skrypcie daje normalne wyjście ( 5 10pokazuje na przykład).

Ponowne uruchomienie niczego nie zmieniło.

Moja wersja bash to GNU bash, wersja 4.3.42 (1) -release (x86_64-pc-linux-gnu). Jestem na Ubuntu 15.10. Nie wiem, jakie inne informacje są tutaj istotne.

ślimak na wyprawie
źródło
16
z <operacją dokonujesz porównania ciągów, podczas gdy -ltoperator jest porównaniem numerycznym, jeśli spojrzysz na wymienione wyniki, zdasz sobie z tego sprawę. Liczbowo 2 to mniej niż 10, alfabetycznie, na odwrót.
MelBurslan

Odpowiedzi:

51

Ze strony podręcznika bash.

W przypadku użycia z [[, operatory <i> sortują leksykograficznie przy użyciu bieżących ustawień regionalnych.

Z wyniku wydaje się, że działa zgodnie z przeznaczeniem.

Steve
źródło
35
Innymi słowy, przeczytaj stronę podręcznika przed założeniem, że znalazłeś błąd. ;)
Wildcard
Prawdziwe. Być może skrypt, nad którym pierwotnie pracowałem, zaczął właściwie działać „poprawnie” (jak w przypadku niepowodzenia [[$ myvar <13]]), kiedy zauważyłem to zachowanie. Czy jest coś, co powinienem teraz zrobić z tym pytaniem? Czy w tej witrynie zmieniamy tytuł na [rozwiązany] lub coś takiego? Czy tytuł należy zmienić na coś bardziej opisowego?
ślimak na wyprawie
2
Nie, nie zmieniaj tytułu pytania. Znacznik wyboru obok tej odpowiedzi wystarczy, aby wskazać, że pytanie zostało rozwiązane.
saiarcot895
14
@Wildcard OP nie zakłada, że ​​znalazł błąd. Wyraźnie sugerują, że być może zrobili coś, aby zmienić zachowanie. Nawet tytuł zakłada tyle samo!
jpmc26
5

Co powiesz na:

for a in {1..5}; 
do     
  for b in {1..20};     
  do         
    (( $a < $b )) && echo $a $b
  done      
  echo
done

Według http://www.tldp.org/LDP/abs/html/dblparens.html

Podobnie jak w przypadku polecenia let, konstrukcja ((...) pozwala na rozszerzanie i ocenę arytmetyczną. W najprostszej postaci a = $ ((5 + 3)) ustawi wartość a na 5 + 3 lub 8. Jednak ta konstrukcja z podwójnymi nawiasami jest również mechanizmem umożliwiającym na przykład manipulację zmiennymi w stylu C w Bash, na przykład , ((var ++)).

PaulSmecker
źródło
2
Nie rozumiesz sedna pytania - nie chodzi o to „jak porównać te wartości?” ale „dlaczego tak się zachowuje?”.
guntbert
7
Na to już odpowiedziano. Ale ponieważ chciał użyć wyrażenia arytmetycznego, warto wskazać, że istnieją konstrukty, które pozwalają na użycie ich w powłoce.
PaulSmecker
3

Po pierwsze, [[ nie jest POSIX i należy go unikać.

Po drugie, jeśli chcesz użyć <jako część testu arytmetycznego, możesz to zrobić, ale z inną składnią:

if [ $((2 < 13)) = 1 ]
then
  echo '2 is less than 13'
else
  echo '2 is greater or equal to 13'
fi

Lub:

if expr 2 '<' 13
then
  echo '2 is less than 13'
else
  echo '2 is greater or equal to 13'
fi
Steven Penny
źródło