Dlaczego podczas gdy [0] przechodzi w nieskończoną pętlę?

23

Widzę to samo zachowanie dla pętli poniżej, jak dla pętli while [ 1 ]. Dlaczego to jest takie?

while [ 0 ]; do
    echo "hello"
done
użytkownik13107
źródło

Odpowiedzi:

33

Pojedyncze nawiasy kwadratowe w powłoce są synonimem test(osobnego polecenia lub wbudowanej powłoki), więc [ 0 ]oznaczają to samo co test 0. testsłuży do przeprowadzania porównań i testowania atrybutów plików, o czym można przeczytać na stronie podręcznika. Jeśli nie zostanie podane wyrażenie, które wygląda jak porównanie, test pliku lub jedna z innych operacji, które może wykonać, zamiast tego przetestuje, czy argument jest obecny i niepusty ciąg znaków. Nie są 0ani nie 1są odpowiednimi danymi wejściowymi do testu, a ponieważ niepuste ciągi znaków po prostu się udają, a pętla while zapętla się na zawsze.

Zamiast tego możesz spróbować

while false; do
  echo "hello"
done

ewentualnie zastępując falsez true. A może chcesz użyć (( )):

while (( 0 )); do
  echo "hello"
done

Które będą się zachowywać jak większość języków, gdzie 0 oznacza błąd / fałsz, a 1 oznacza sukces / prawda.

wingedsubmariner
źródło
1
Re: „Kiedy nie ma wyrażenia, które wygląda jak porównanie, test pliku lub jedna z innych operacji, które można wykonać, po prostu się udaje”: Nie sądzę, żeby to był dobry sposób. W końcu [ ](bez argumentu) i [ "" ](z jednym pustym argumentem) nie udaje się.
ruakh
3
Jak wyjaśnia @ruakh, to stwierdzenie jest błędne: jeśli nie ma wyrażenia, które wygląda jak porównanie, test pliku lub jedna z innych operacji, które można wykonać, po prostu się udaje. Każdy pojedynczy argument testu (dowolny pojedynczy argument wewnątrz nawiasów kwadratowych) jest uważany TRUE, jeśli argument nie jest pusty ciąg znaków, a zarówno 0i 1nie są puste ciągi. Nowi programiści powłoki często piszą if [ 1=2 ]zamiast if [ 1 = 2 ]i zastanawiają się, dlaczego to pierwsze jest zawsze prawdziwe. To prawda, ponieważ jest to pojedynczy argument i nie jest pustym ciągiem.
Ian D. Allen
Dobrze, poprawiłem.
wingedsubmariner
10

Wartość 0 nie działa tutaj jako stała liczbowa, ale jako ciąg znaków. Wszystkie te testy są równoważne pod względem efektu pomyślnego zakończenia połączenia:

[ A ]
[ "XYZ" ]
[ 0 ]

generują one status zakończonego niepowodzeniem:

[ ]
[ "" ]

istnieje niepusty argument, który daje logiczną wartość prawda. To pozwala ci robić takie rzeczy jak:

if [ $UNDER_NUCLEAR_ATTACK ] ; then
  launch-missiles -a $DRY_RUN  # $DRY_RUN set to "-n" during testing
fi

Zmienna UNDER_NUCLEAR_ATTACKjest ustawiona na dowolną niepustą wartość, aby wskazać wartość true, lub jest nieustawiona lub pusta, aby wskazać wartość false.

Możemy zastosować !operatora do odwrócenia logiki:

[ ! a ]  # fails: a is nonblank so true; and not true is false.
[ ! ]    # succeeds: blank is false, not blank is true.

Aby ocenić warunek numeryczny, musisz użyć numerycznych operatorów testowych:

 while [ $A -gt $B ] ; do ...

Jeśli Ai Bzawierają ciągi, które wyglądają jak dziesiętne liczby całkowite, są one porównywane jak liczby, a jeśli Ajest większe niż B, pętla wykonuje się. Załóżmy więc, że UNDER_NUCLEAR_ATTACKnie jest to boolean typu łańcuchowego, który jest pusty lub niepusty, ale w rzeczywistości boolean numeryczny, który ma wartość 0(false) lub inną wartość (true). W takim przypadku napisalibyśmy test w ten sposób:

 if [ $UNDER_NUCLEAR_ATTACK -ne 0 ] ; then ...
Kaz
źródło
-1

Konstrukcja if / then sprawdza, czy status wyjścia listy poleceń wynosi 0 (ponieważ 0 oznacza „sukces” zgodnie z konwencją UNIX), a jeśli tak, wykonuje jedno lub więcej poleceń.

Krótko mówiąc, zwracasz wynik testu równy zero.

http://www.tldp.org/LDP/abs/html/testconstructs.html

Stephan
źródło
5
Tak, ale nie z powodu, dla którego wydajesz się myśleć. Jeśli [dostaje tylko jeden argument ( ]oczywiście z wyłączeniem ), to kończy się ze statusem zero, jeśli argument nie jest pusty, a niezerowy, jeśli tak jest. Na przykład [ 1 ]zwróci również kod wyjścia z 0.
Kevin
-1

Wartość 0 jest uważana za prawdę dla pętli while, dlatego warunek dla pętli while jest prawdziwy, a zatem ciągłe wyświetlanie pętli nieskończonej. Jest to prawdą, jeśli zamieniamy 0 na 1, ponieważ każda liczba całkowita, którą zapisujemy między warunkiem, zwróci true

Jyoti Minhas
źródło