$ phone_missing é uma string que contém "false". E uma string não vazia é avaliada como verdadeira. Veja também link
phone_missing=false
echo "missing $phone_missing"
if [ ! $phone_missing ]
then
echo "Lost phone at $readabletime"
$phone_missing=true
fi
Eu simplesmente não consigo envolver minha cabeça com isso, por mais idiota que possa parecer. A linha
echo "missing $phone_missing"
echos missing false
, eu esperaria muito que a declaração
if [ ! $phone_missing ]
seja verdadeiro e insira a cláusula if
, mas isso não acontece? O que estou perdendo aqui?
$ phone_missing é uma string que contém "false". E uma string não vazia é avaliada como verdadeira. Veja também link
Costumo usar "true" e "false", pois eles também são comandos que meramente retornam sucesso e falha, respectivamente. Então você pode fazer
if "$phone_missing"; then ...
Aqui está uma maneira de fazer isso, mantendo os valores verdadeiro / falso.
phone_missing=false
if [ "$phone_missing" != false ]; then
echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == true ]; then
echo "phone_missing is true."
fi
As aspas duplas em torno de $phone_missing
são para proteger contra o caso em que a variável phone_missing
não está definida. Outro idioma comum para evitar isso é [ x$phone_missing != xfalse ]
, mas as citações parecem mais naturais para mim.
A dica está na página de ajuda bash
de test
:
STRING True if string is not empty. ... ! EXPR True if expr is false.
Então, basicamente, [ $foo ]
será verdadeiro se $foo
não estiver vazio. Não é verdade ou falsa, apenas não vazia. [ ! $foo ]
é verdadeiro se $ foo estiver vazio ou indefinido.
Você sempre pode alterar seu código para definir apenas phone_missing
como um valor não vazio, o que denota true. Se phone_missing
não estiver definido (ou vazio - phone_missing=""
), será falso. Caso contrário, você deve estar usando os operadores de teste de string ( =
e !=
).
O outro pequeno problema é a atribuição. Você tem isso como $phone_missing=true
, enquanto deveria ser phone_missing=true
(sem sinal de dólar).
Desculpe se isso é um pouco denso, é porque eu sou. Tem sido um longo dia. :)
Eu teria feito isso como um comentário para apoiar James Ko, mas não tinha o representante para comentar ou votar publicamente.
O problema aqui é que os colchetes [] são notados para fazer um teste de comparação, como valor ou igualdade de string.
A exatidão de string no bash para uma string vazia é ""
(string vazia) avaliada como false (valor de retorno 1) e qualquer string não vazia "false" "true" ou "bob's your tcle" é avaliada como true 0).
Você pode provar isso para si mesmo com:
if [ "foo" ]; then
echo true is $?;
else
echo false is $?;
fi
O $?
acima é uma variável especial que mantém o status de saída dos últimos comandos (0 com êxito e qualquer > 0 para código de erro) e emitirá true is 0
. Você pode substituir "foo"
com o que quiser e o resultado será o mesmo, exceto se você substituí-lo por uma string vazia ""
ou ''
, caso em que avaliará a condição else e a saída false is 1
.
Ao usar os colchetes [], a declaração interna, como! $ phone_missing é avaliado e, em seguida, retorna um 0
para true ou 1
para false para a instrução de controle if. Como o colchete avalia as comparações de string e valor, o $ phone_missing é primeiro expandido para a string não vazia "false", que é avaliada pelo [] como uma string não vazia (ou verdadeira) e, em seguida, o! inverte o resultado que resulta na instrução if obtendo um valor false (ou valor de retorno 1) e pula o corpo condicional executando a instrução else se presente.
Como James Ko disse, a notação seria apenas passar a variável mantendo seu 'booleano' para a declaração de controle if. Note que no bash um booleano verdadeiro e falso deve ser minúsculo como em: bool_true = true bool_false = false Qualquer outro caso será avaliado como strings e não como booleano.
Então, usando o seu exemplo e a resposta de James Ko, seria:
phone_missing=false
echo "missing $phone_missing"
if ! $phone_missing
then
echo "Lost phone at $readabletime"
$phone_missing=true
fi
ou como eu prefiro ler (sintaticamente o mesmo e o de James Ko)
phone_missing=false
echo "missing $phone_missing"
if ( ! $phone_missing ); then
echo "Lost phone at $readabletime"
$phone_missing=true
fi
Outras respostas, como as de Alexios, estão literalmente verificando o conteúdo da string. De modo que qualquer um dos seguintes resultaria em falso:
phone_missing=false
if [ "$phone_missing" != false ]; then
echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == true ]; then
echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == Bobs_your_uncle ]; then
echo "phone_missing is not 'false' (but may be non-true, too)"
fi
Outras respostas deram solução, mas vou explicar o que havia de errado com o pensamento original.
Variáveis Bash não possuem tipos, portanto não existe uma variável booleana ou valor como true ou false. Basicamente, todas as variáveis bash são apenas strings.
Quando você testa uma variável / string no bash sem especificar o tipo de teste ( -n
ou -z
), o padrão será um teste -n
(string de comprimento diferente de zero).
Portanto, [ "$var" ]
é equivalente a [ -n "$var" ]
. Desde que $var
contenha pelo menos 1 caractere, foi avaliado como verdadeiro.
Como você negou a expressão, [ ! "$var" ]
é equivalente a [ ! -n "$var" ]
. Portanto, se $var
contiver pelo menos 1 caractere, a expressão será falsa.
Como false
(que é apenas uma string) contém 5 caracteres, a expressão é falsa. Se não importa qual cadeia você definiu phone_missing
para ( true
, 0, 1), a expressão será sempre false
porque é phone_missing
é diferente de zero. A única maneira de torná-lo true
é phone_missing=""
, já que é o comprimento zero.
Não use string para booleano. Use inteiro.
Entrada:
val=1
((val)) && echo "true" || echo "false"
val=0
((val)) && echo "true" || echo "false"
Saída:
true
false
Fonte :
((expression))
The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION. If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1. This is exactly equivalent to let "expression".
A sintaxe correta é if ! $bool; then [statements]; fi
.
Exemplo:
bool=false
if ! $bool; then
echo "This is correct!"
fi
if [ ! $bool ]; then
echo "This is wrong!"
fi
Saída: This is correct!