Inverte a variável booleana

20

Eu quero tentar um script simples

flag=false
while !$flag
do
   read x
   if [ "$x" -eq "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

Mas quando eu executo, se eu digitar true , verei que x="true" e flag="true" , mas o ciclo não termina. O que há de errado com o roteiro? Como posso inverter corretamente uma variável booleana?

    
por user253202 12.11.2011 / 23:58

5 respostas

18

Existem dois erros no seu script. A primeira é que você precisa de um espaço entre ! e $flag , caso contrário, o shell procura um comando chamado !$flag . O segundo erro é que -eq é para comparações de inteiros, mas você está usando em uma string. Dependendo do seu shell, você verá uma mensagem de erro e o loop continuará para sempre porque a condição [ "$x" -eq "true" ] não pode ser verdadeira ou todo valor não inteiro será tratado como 0 e o loop será encerrado se você inserir uma string (incluindo false ) diferente de um número diferente de 0.

Embora ! $flag esteja correto, é uma má idéia tratar uma string como um comando. Funcionaria, mas seria muito sensível às alterações no seu script, já que você precisaria garantir que $flag nunca seja nada, exceto true ou false . Seria melhor usar uma comparação de string aqui, como no teste abaixo.

flag=false
while [ "$flag" != "true" ]
do
   read x
   if [ "$x" = "true" ]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

Há provavelmente uma maneira melhor de expressar a lógica que você procura. Por exemplo, você poderia fazer um loop infinito e quebrá-lo quando detectar a condição de término.

while true; do
  read -r x
  if [ "$x" = "true" ]; then break; fi
  echo "$x: false"
done
    
por 13.11.2011 / 00:24
9

Embora não haja variáveis booleanas no Bash, é muito fácil imitá-las usando a avaliação aritmética.

flag= # False
flag=0 # False
flag=1 # True (actually any integer number != 0 will do, but see remark below about toggling)
flag="some string" # Maybe False (make sure that the string isn't interpreted as a number)

if ((flag)) # Test for True
then
  : # do something
fi

if ! ((flag)) # Test for False
then
  : # do something
fi

flag=$((1-flag)) # Toggle flag (only works when flag is either empty or unset, 0, 1, or a string which doesn't represent a number)

Isso também funciona no ksh. Eu não ficaria surpreso se ele funcionasse em todos os shells compatíveis com POSIX, mas não tivesse verificado o padrão.

    
por 30.09.2014 / 19:16
3

Se você pode ter certeza absoluta de que a variável conterá 0 ou 1, você pode usar o operador bit a bit XOR-equal para alternar entre os dois valores:

$ foo=0
$ echo $foo
0
$ ((foo ^= 1))
$ echo $foo
1
$ ((foo ^= 1))
$echo $foo
0
    
por 11.05.2017 / 21:04
2

Isso funciona para mim:

flag=false
while [[ "$flag" == "false" ]]
do
   read x
   if [[ "$x" == "true" ]]
   then
     flag=true
   fi
   echo "${x} : ${flag}"
done

Mas, na verdade, o que você deve fazer é substituir seu while por:

while ! $flag
    
por 13.11.2011 / 00:07
-1
[ ${FOO:-0} == 0 ] && FOO=1 || FOO=0

ou até mesmo:

[ ${FOO:-false} == false ] && FOO=true || FOO=false

deve fazer o trabalho

    
por 28.07.2015 / 00:14