Por que enquanto [0] entra em loop infinito?

23

Eu vejo o mesmo comportamento para o loop abaixo do loop com while [ 1 ]. Por que?

while [ 0 ]; do
    echo "hello"
done
user13107
fonte

Respostas:

33

Colchetes simples no shell é sinônimo de test(comando separado ou interno do shell), portanto [ 0 ]significa a mesma coisa que test 0. testé para fazer comparações e testar os atributos dos arquivos, como você pode ler em sua página de manual. Quando não recebe uma expressão que se parece com uma comparação, teste de arquivo ou uma das outras operações que pode ser executada, ela testará se o argumento está presente e uma sequência não vazia. Nem 0ou 1são entradas realmente apropriados para o teste, e como strings não vazias teste simplesmente sucede e seu loop while loop para sempre.

Você pode tentar

while false; do
  echo "hello"
done

possivelmente substituindo falsepor true. Ou talvez o que você queira seja usar (( )):

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

Que se comportará como a maioria dos idiomas, onde 0 significa falha / falso e 1 significa sucesso / verdadeiro.

wingedsubmariner
fonte
1
Re: "Quando não é dada uma expressão que se parece com uma comparação, teste de arquivo ou uma das outras operações que ela pode fazer, ela simplesmente é bem-sucedida": não acho que seja uma boa maneira de colocar isso. Afinal, [ ](sem argumento) e [ "" ](com um único argumento vazio) não obtêm êxito.
Ruakh 22/10
3
Como @ruakh explica, esta afirmação está errada: quando não é dada uma expressão que se parece com uma comparação, teste de arquivo ou uma das outras operações que ela pode executar, ela simplesmente é bem-sucedida. Qualquer argumento único a ser testado (qualquer argumento entre colchetes) é considerado VERDADEIRO se o argumento não for uma string vazia, e ambas 0e 1não forem strings vazias. Novos programadores shell muitas vezes escrever if [ 1=2 ]em vez de if [ 1 = 2 ]e admira por isso que o primeiro é sempre verdadeiro. É verdade porque é um argumento único e não é uma string vazia.
Ian D. Allen
Bons pontos, eu fiz uma correção.
wingedsubmariner
10

O valor 0 aqui não está atuando como uma constante numérica, mas como uma sequência de caracteres. Esses testes são todos equivalentes no efeito de produzir um status de finalização bem-sucedido:

[ A ]
[ "XYZ" ]
[ 0 ]

estes produzem um status de terminação com falha:

[ ]
[ "" ]

existe um argumento não em branco, que avalia como verdadeiro lógico. Isso permite que você faça coisas como:

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

A variável UNDER_NUCLEAR_ATTACKé configurada para qualquer valor que não esteja em branco para indicar true ou está desabilitada ou vazia para indicar false.

Podemos aplicar o !operador para reverter a lógica:

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

Para avaliar uma condição numérica, você deve usar operadores de teste numérico:

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

Se Ae Bcontiverem seqüências de caracteres que pareçam números inteiros decimais, elas serão comparadas como números e, se Afor maior que B, o loop será executado. Portanto, suponha que UNDER_NUCLEAR_ATTACKnão seja um booleano do tipo string que esteja em branco ou não em branco, mas na verdade um booleano numérico que seja 0(false) ou algum outro valor (true). Nesse caso, escreveríamos o teste assim:

 if [ $UNDER_NUCLEAR_ATTACK -ne 0 ] ; then ...
Kaz
fonte
-1

Uma construção if / then testa se o status de saída de uma lista de comandos é 0 (já que 0 significa "sucesso" pela convenção UNIX) e, nesse caso, executa um ou mais comandos.

Em resumo, você está retornando um resultado de teste igual a zero.

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

Stephan
fonte
5
Sim, mas não pela razão que parece pensar. Se [obtiver apenas um argumento (excluindo o ], é claro), ele sairá com status zero se o argumento não estiver vazio, diferente de zero se estiver. Então, por exemplo, [ 1 ]também retornará um código de saída de 0.
22413 Kevin
-1

O valor 0 é considerado como verdadeiro para o loop while, portanto, a condição para o loop while é verdadeira e, portanto, continua a mostrar o loop infinito. O é verdadeiro se substituirmos 0 por 1, pois qualquer número inteiro que escrevermos entre a condição retornará verdadeiro

Jyoti Minhas
fonte