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 o executar, se eu digitar true
, verei isso x="true"
e flag="true"
, mas o ciclo não termina. O que há de errado com o script? Como posso inverter adequadamente uma variável booleana?
Respostas:
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 é-eq
para comparações de números inteiros, mas você o 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ê digitar qualquer string (incluindofalse
) diferente de um número diferente de 0.Enquanto
! $flag
estiver correto, é uma má idéia tratar uma string como um comando. Funcionaria, mas seria muito sensível a alterações em seu script, pois você precisa garantir que isso$flag
nunca pode ser outra coisa senãotrue
oufalse
. Seria melhor usar uma comparação de cadeias aqui, como no teste abaixo.Provavelmente existe uma maneira melhor de expressar a lógica que você procura. Por exemplo, você pode fazer um loop infinito e interrompê-lo quando detectar a condição de finalização.
fonte
[
builtin deksh
,[ x -eq y ]
retorne true se ax
expressão aritmética resolver para o mesmo número que ay
expressão aritmética, por exemplox=2 true=1+1 ksh -c '[ x -eq true ] && echo yes'
, produzirá sim.Embora não haja variáveis booleanas no Bash, é muito fácil imitá-las usando a avaliação aritmética.
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.
fonte
! ! ((val))
no Bash, como em C ou C ++? Por exemplo, seval
for 0, permanecerá 0 depois! !
. Seval
for 1, permanece 1 depois! !
. Seval
for 8, é reduzido para 1 depois! !
. Ou preciso fazer outra pergunta?Se você tiver certeza absoluta de que a variável conterá 0 ou 1, use o operador igual a XOR bit a bit para alternar entre os dois valores:
fonte
Isso funciona para mim:
Mas, na verdade, o que você deve fazer é substituir o seu
while
por:fonte
Não há conceito de uma variável booleana no shell.
Variáveis do shell só poderia ser
text
(uma string), e, em alguns casos, esse texto pode ser interpretado como um inteiro (1
,0xa
,010
, etc.).Portanto, a
flag=true
não implica em veracidade ou falsidade para a concha.Corda
O que poderia ser feito é uma comparação de cadeias
[ "$flag" == "true" ]
ou usar o conteúdo da variável em algum comando e verificar suas conseqüências , como executetrue
(porque há um executável chamadotrue
e um chamadofalse
) como um comando e verifique se o código de saída desse comando é zero (bem sucedido).Ou mais curto:
Se o conteúdo de uma variável for usado como um comando, a
!
poderá ser usado para negar o status de saída do comando, se existir um espaço entre ambos (! cmd
), como em:O script deve mudar para:
Inteiro
Use valores numéricos e expansões aritméticas .
Nesse caso, o código de saída de
$((0))
é1
e o código de saída de$((1))
é0
.No bash, ksh e zsh, a aritmética pode ser realizada dentro de um
((..))
(observe que a partida$
está faltando).flag=0; if ((flag)); then ... fi
Uma versão portátil deste código é mais complicada:
No bash / ksh / zsh, você pode fazer:
alternativamente
Você pode "Inverter uma variável booleana" (desde que contenha um valor numérico) como:
((flag=!flag))
Isso mudará o valor de
flag
para ou0
ou1
.Nota : Verifique se há erros em https://www.shellcheck.net/ antes de postar seu código como uma pergunta, muitas vezes o suficiente para encontrar o problema.
fonte
until
é a abreviação dewhile !
(euntil
, ao contrário de!
Bourne), então você pode fazer:Qual deve ser o mesmo que:
Você também pode escrever como:
A parte entre
until
/while
edo
não precisa ser um único comando.!
é uma palavra-chave na sintaxe do shell POSIX. Ele precisa ser delimitado, um token separado do que segue e ser o primeiro token que precedeu um pipeline (! foo | bar
nega o pipeline efoo | ! bar
é inválido, embora alguns shells o aceitem como uma extensão).!true
é interpretado como o!true
comando que é improvável que exista.! true
Deveria trabalhar.!(true)
deve funcionar em shells compatíveis com POSIX, pois!
é delimitado por um(
token, mas, na prática, não funciona emksh
/bash -O extglob
onde conflita com o!(pattern)
operador glob estendido nem o zsh (exceto na emulação sh) onde conflitaglob(qualifiers)
combareglobqual
eglob(group)
sem.fonte
ou até:
deve fazer o trabalho
fonte