Como posso declarar e usar variáveis ​​booleanas em um script de shell?

980

Tentei declarar uma variável booleana em um script de shell usando a seguinte sintaxe:

variable=$false

variable=$true

Isso está correto? Além disso, se eu quisesse atualizar essa variável, usaria a mesma sintaxe? Finalmente, a sintaxe a seguir para usar variáveis ​​booleanas como expressões está correta?

if [ $variable ]

if [ !$variable ]
hassaanm
fonte
73
Cuidado! truee falseno contexto da maioria dos trechos abaixo, são apenas strings simples, não o bash built-ins!!! Por favor, leia a resposta de Mike Holt abaixo. (Este é um exemplo onde um altamente votou e resposta aceita é IMHO confuso e sombras conteúdo perspicaz em menor votado respostas)
mjv
7
@mjv A maior parte da confusão sobre essa pergunta (e a resposta de Miku) deveu-se ao fato de Miku revisar sua resposta em algum momento após vários comentários serem publicados, descrevendo como a resposta de Miku envolveu chamar o bash de built-in true. Acontece que a resposta original de Miku realmente chamou o truebuilt-in, mas a resposta revisada não. Isso fez com que os comentários parecessem errados sobre o funcionamento do código de Miku. A resposta de Miku foi editada para mostrar explicitamente o código original e o revisado. Esperemos que isso acabe com a confusão de uma vez por todas.
21815 Mike Holt
2
[ true ] && echo yes, true is truee (upppsss) [ false ] && echo yes, false is also true. / bin / true e / bin / false fornece um código de retorno $? para funções não para comparação.
precisa saber é
Se var é definido variable=somethingcomo verdadeiro, se não definido , variable=isso seria falso [[ $variable ]] && echo true || echo falsee reverso[[ ! $variable ]] && echo false || echo true
Ivan

Respostas:

1202

Resposta Revisada (12 de fevereiro de 2014)

the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
    echo 'Be careful not to fall off!'
fi

Resposta original

Advertências: https://stackoverflow.com/a/21210966/89391

the_world_is_flat=true
# ...do something interesting...
if $the_world_is_flat ; then
    echo 'Be careful not to fall off!'
fi

De: usando variáveis ​​booleanas no Bash

A razão pela qual a resposta original foi incluída aqui é porque os comentários anteriores à revisão em 12 de fevereiro de 2014 pertencem apenas à resposta original e muitos dos comentários estão errados quando associados à resposta revisada. Por exemplo, o comentário de Dennis Williamson sobre o bash embutido trueem 2 de junho de 2010 se aplica apenas à resposta original, não à revisada.

miku
fonte
37
Para explicar o que está acontecendo: a ifinstrução está executando o conteúdo da variável que é o Bash embutido true. Qualquer comando poderia ser definido como o valor da variável e seu valor de saída seria avaliado.
Pausado até novo aviso.
7
@pms Os operadores "-o" e "-a" são apenas para o comando "test" (também conhecido como "[]"). Em vez disso, este é "if + command", sem o "test". (Como "if grep foo file; then ...".) Portanto, use o normal &&e os ||operadores: # t1=true; t2=true; f1=false;# if $t1 || $f1; then echo is_true ; else echo is_false; fi; (retorna "true", pois t1 = true) # if $t1 && $f1 || $t2; then echo is_true ; else echo is_false; fi (retorna "true", pois t2 = true) . Novamente, isso APENAS funciona porque "true" / "false" são bash-builtins (retornando true / false). Você não pode usar "if $ var ..." a menos var é um cmd (ou seja, verdadeiro ou falso)
michael
14
-1, veja minha resposta para uma explicação.
Dennis
3
Muitas informações incorretas, aqui. / bin / true não está sendo usado efetivamente. Veja a resposta de Dennis.
ajk
1
Este código não é o mesmo e não funciona da mesma maneira que o artigo vinculado. O código vinculado chama um programa pelo nome armazenado em uma variável, mas o código nesta resposta é apenas uma comparação de cadeias.
Quolonel Questions
794

TL; DR

bool=true

if [ "$bool" = true ]

Problemas com a resposta de Miku ( original )

Eu não recomendo a resposta aceita 1 . Sua sintaxe é bonita, mas tem algumas falhas.

Digamos que temos a seguinte condição.

if $var; then
  echo 'Muahahaha!'
fi

Nos seguintes casos 2 , essa condição será avaliada como verdadeira e executará o comando aninhado.

# Variable var not defined beforehand. Case 1
var=''  # Equivalent to var="".        Case 2
var=    #                              Case 3
unset var  #                           Case 4
var='<some valid command>'  #          Case 5

Normalmente, você deseja que sua condição seja avaliada como verdadeira apenas quando sua variável "Boolean", varneste exemplo, estiver explicitamente definida como verdadeira. Todos os outros casos são perigosamente enganosos!

O último caso (# 5) é especialmente impertinente, porque executará o comando contido na variável (é por isso que a condição é avaliada como verdadeira para comandos válidos 3, 4 ).

Aqui está um exemplo inofensivo:

var='echo this text will be displayed when the condition is evaluated'
if $var; then
  echo 'Muahahaha!'
fi

# Outputs:
# this text will be displayed when the condition is evaluated
# Muahahaha!

Citar suas variáveis ​​é mais seguro, por exemplo if "$var"; then. Nos casos acima, você deve receber um aviso de que o comando não foi encontrado. Mas ainda podemos fazer melhor (veja minhas recomendações na parte inferior).

Veja também a explicação de Mike Holt da resposta original de Miku.

Problemas com a resposta da Hbar

Essa abordagem também tem um comportamento inesperado.

var=false
if [ $var ]; then
  echo "This won't print, var is false!"
fi

# Outputs:
# This won't print, var is false!

Você esperaria que a condição acima fosse avaliada como falsa, portanto, nunca executando a instrução aninhada. Surpresa!

Citar o valor ( "false"), citar a variável ( "$var") ou usar testou em [[vez de [não faz diferença.

O que eu não recomendo:

Aqui estão algumas maneiras pelas quais eu recomendo que você verifique seus "booleanos". Eles funcionam como esperado.

bool=true

if [ "$bool" = true ]; then
if [ "$bool" = "true" ]; then

if [[ "$bool" = true ]]; then
if [[ "$bool" = "true" ]]; then
if [[ "$bool" == true ]]; then
if [[ "$bool" == "true" ]]; then

if test "$bool" = true; then
if test "$bool" = "true"; then

Eles são todos praticamente equivalentes. Você precisará digitar mais algumas teclas do que as abordagens nas outras respostas 5 , mas seu código será mais defensivo.


Notas de rodapé

  1. A resposta de Miku foi editada e não contém mais falhas (conhecidas).
  2. Não é uma lista exaustiva.
  3. Um comando válido neste contexto significa um comando que existe. Não importa se o comando é usado corretamente ou incorretamente. Por exemplo man woman, ainda seria considerado um comando válido, mesmo que não exista essa página de manual.
  4. Para comandos inválidos (inexistentes), o Bash simplesmente reclamará que o comando não foi encontrado.
  5. Se você se preocupa com o comprimento, a primeira recomendação é a mais curta.
Dennis
fonte
8
Usando ==com [ou testnão é portátil. Considerando a portabilidade é a única vantagem [/ testsuperação [[, permaneça com =.
usar o seguinte código
2
@ Scott Eu uso o peixe como meu shell principal, que tem uma linguagem de script sã em comparação com o bash na minha opinião.
Dennis
1
Sim, eu simplesmente não conseguia encontrar nos comentários qualquer apreço por esta piada escondida, tiveram de indicá-lo =)
Kranach
5
Para mim, conceitualmente, é mais fácil entender se eu uso bool = "true". Então fica claro que é apenas uma string e não algum valor especial ou embutido.
wisbucky
1
@dolmen absolutamente, avaliar a entrada não é tão arriscado quando você controla a entrada, mas ainda considero uma prática ruim que deve ser evitada se puder ser facilmente evitada. Alguém que só viu e usou o estilo anterior pode não conhecer suas falhas, o que pode causar um comportamento inesperado.
Dennis
175

Parece haver algum mal-entendido aqui sobre o Bash embutido truee, mais especificamente, sobre como o Bash expande e interpreta expressões entre colchetes.

O código na resposta de Miku não tem absolutamente nada a ver com o embutido Bash true, nem /bin/true, nem qualquer outro sabor do truecomando. Nesse caso, truenada mais é do que uma simples cadeia de caracteres e truenunca é feita nenhuma chamada ao comando / builtin, nem pela atribuição da variável nem pela avaliação da expressão condicional.

O código a seguir é funcionalmente idêntico ao código na resposta do miku:

the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
    echo 'Be careful not to fall off!'
fi

A única diferença aqui é que os quatro caracteres comparados são 'y', 'e', ​​'a' e 'h' em vez de 't', 'r', 'u' e 'e'. É isso aí. Não é feita nenhuma tentativa de chamar um comando ou um nome interno yeah, nem existe (no exemplo do miku) nenhum tipo de tratamento especial acontecendo quando o Bash analisa o token true. É apenas uma string e completamente arbitrária.

Atualização (19/02/2014): Depois de seguir o link na resposta do miku, agora vejo de onde vem parte da confusão. A resposta de Miku usa colchetes simples, mas o trecho de código ao qual ele vincula não usa colchetes. É apenas:

the_world_is_flat=true
if $the_world_is_flat; then
  echo 'Be careful not to fall off!'
fi

Ambos os trechos de código se comportam da mesma maneira, mas os colchetes mudam completamente o que está acontecendo sob o capô.

Aqui está o que Bash está fazendo em cada caso:

Sem colchetes:

  1. Expanda a variável $the_world_is_flatpara a sequência "true".
  2. Tente analisar a cadeia "true"como um comando.
  3. Encontre e execute o truecomando (embutido ou /bin/true, dependendo da versão do Bash).
  4. Compare o código de saída do truecomando (que é sempre 0) com 0. Lembre-se de que na maioria dos shells, um código de saída 0 indica sucesso e qualquer outra coisa indica falha.
  5. Como o código de saída foi 0 (êxito), execute a cláusula ifda instruçãothen

Suportes:

  1. Expanda a variável $the_world_is_flatpara a sequência "true".
  2. Analisar a expressão condicional agora totalmente expandida, que é da forma string1 = string2. O =operador é o operador de comparação de strings do bash . Assim...
  3. Faça uma comparação de cadeias em "true"e "true".
  4. Sim, as duas cadeias eram iguais, portanto o valor da condicional é verdadeiro.
  5. Execute a cláusula ifda instrução then.

O código sem colchetes funciona, porque o truecomando retorna um código de saída 0, que indica sucesso. O código entre colchetes funciona, porque o valor de $the_world_is_flaté idêntico à string literal trueno lado direito do =.

Apenas para esclarecer as questões, considere os dois trechos de código a seguir:

Este código (se executado com privilégios de root) irá reiniciar o seu computador:

var=reboot
if $var; then
  echo 'Muahahaha! You are going down!'
fi

Este código apenas imprime "Boa tentativa". O comando reboot não é chamado.

var=reboot
if [ $var ]; then
  echo 'Nice try.'
fi

Atualização (14-04-2014) Para responder à pergunta nos comentários sobre a diferença entre =e ==: AFAIK, não há diferença. O ==operador é um sinônimo específico do Bash =e, até onde eu vi, eles funcionam exatamente da mesma forma em todos os contextos.

Note, no entanto, que eu estou falando especificamente sobre os =e ==operadores de comparação de string usado em qualquer [ ]ou [[ ]]testes. Não estou sugerindo isso =e ==são intercambiáveis em todos os lugares no bash.

Por exemplo, você obviamente não pode fazer a atribuição de variáveis ==, como var=="foo"(bem, tecnicamente, você pode fazer isso, mas o valor de varserá "=foo", porque Bash não está vendo um ==operador aqui, está vendo um =operador (de atribuição), seguido por o valor literal ="foo", que acaba de se tornar "=foo").

Além disso, embora =e ==são intercambiáveis, você deve ter em mente que a forma como esses testes trabalho não depende se você estiver usando-o dentro [ ]ou [[ ]], e também sobre se ou não os operandos são cotados. Você pode ler mais sobre isso no Advanced Bash Scripting Guide: 7.3 Outros operadores de comparação (role para baixo até a discussão sobre =e ==).

Mike Holt
fonte
A abordagem sem suporte também tem a vantagem de permitir que você escrever limpas e claras (IMO) one-liners como$the_world_is_flat && echo "you are in flatland!"
AJK
9
Verdade. Embora eu não esteja defendendo (ou contra) qualquer uma das abordagens. Eu só queria esclarecer algumas das informações erradas que estão sendo votadas aqui, para que as pessoas que se deparam com esse tópico mais tarde não saiam com um monte de conceitos errados sobre como tudo isso funciona.
Mike Holt
1
A razão para a confusão é que a resposta original de miku permaneceu por 4 anos. Todas as referências ao trueconstruído foram feitas com relação à resposta original. (A resposta revisada em 12 de fevereiro de 2014 não foi enviada por miku.) Editei a resposta para incluir o original e o revisado. Então os comentários das pessoas fazem sentido.
wisbucky
1
Ao ler as respostas oferecidas aqui, tenho a impressão de que não existe o real true. Há algum jeito? Suspeito que muitos programadores que estão acostumados a linguagens mais rígidas visualizando essa resposta para ajudá-los a misturar um pouco de bashcola para facilitar um pouco a vida deles desejem um ===operador para que strings e "booleanos" não sejam realmente intercambiáveis. Se eles se ater apenas a 0 e 1 e uso (( $maybeIAmTrue ))como sugerido na Quolonel Pergunta de resposta ?
SeldomNeedy
2
Para abordar o comentário de SeldomNeedy, sim, você pode usar o real true, mas geralmente não como algo para comparar uma variável, uma vez que o real truenão tem valor em si. Tudo o que faz é definir o status de saída para 0, indicando sucesso. Vale a pena notar que é essencialmente equivalente ao chamado "comando nulo", ou :. Quanto a usar 0e 1, é o que faço em todos os meus scripts nos dias de hoje em que preciso de booleanos. E eu uso o (( ))operador em vez de [[ ]]avaliar. Então, por exemplo, se eu tiver flag=0, eu posso fazer #if (( flag )); then ...
Mike Holt
57

Use expressões aritméticas.

#!/bin/bash

false=0
true=1

((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true

Resultado:

verdadeiro
não falso

Quolonel Questions
fonte
3
pros: (1.) o comportamento é semelhante ao modo de C de manipular bools, (2.) a sintaxe é muito concisa / mínima (não requer uma variável à direita e operadores como '=' ou '=='), (3 .) <subjetiva> para mim eu entendo o que acontece sem uma explicação prolixo ... contraste com Miku e Dennis respostas que tanto parecem requerer explicações prolixo </ subjetiva>
Trevor Boyd Smith
3
@TrevorBoydSmith Por que você não disse apenas "profissionais: tudo, contras: nada". Economizaria custos de depreciação no teclado e no monitor a longo prazo.
Quolonel Perguntas
4
Para uso interativo, como one-liners, certifique-se de deixar um espaço depois !ou ele fará a expansão do histórico. ((! foo))funciona, o mesmo acontece ! ((foo)). Eu amo essa solução, BTW. Finalmente, uma maneira concisa de fazer variáveis ​​booleanas. ((foo || bar))funciona como esperado.
Peter Cordes
5
(())expande variáveis ​​recursivamente, o que eu não esperava. foo=bar; bar=baz; ((foo)) && echo echoimprime nada, mas é verdade com baz=1. Assim, você pode apoiar foo=truee foo=falsetambém 0 ou 1 fazendo true=1.
Peter Cordes
2
@quolonel obrigado pelo recurso muito útil. É claro que meu entendimento é limitado - é da natureza humana ser limitado em todo entendimento, não importa o domínio. No entanto, você se importaria em me dizer quais das minhas declarações o levam a supor que minha compreensão desse assunto em particular é incompleta?
Hubert Grzeskowiak 3/11
34

Longa história curta:

Não há booleanos no Bash

O Bash tem expressões booleanas em termos de comparação e condições. Dito isto, o que você pode declarar e comparar no Bash são strings e números. É isso aí.

Onde quer que você veja trueou falseno Bash, é uma string ou um comando / builtin que é usado apenas para o código de saída.

Essa sintaxe ...

if true; then ...

é essencialmente ...

if COMMAND; then ...

A condição é verdadeira sempre que o comando retorna o código de saída 0. trueE falsesão programas internos do Bash e, às vezes, também programas independentes que não fazem nada além de retornar o código de saída correspondente.

O condicional acima é equivalente a:

COMMAND && ...

Ao usar colchetes ou o testcomando, você depende do código de saída dessa construção. Lembre-se disso [ ]e [[ ]]também são apenas comandos / componentes internos como qualquer outro. Assim ...

if [[ 1 == 1 ]]; then echo yes; fi

corresponde a

if COMMAND; then echo yes; fi

e o COMMANDaqui é[[ 1 == 1 ]]

A if..then..ficonstrução é apenas açúcar sintático. Você sempre pode apenas executar os comandos separados por um e comercial duplo para o mesmo efeito:

[[ 1 == 1 ]] && echo yes

Ao usar truee falsenessas construções de teste, você está realmente apenas passando a string "true"ou "false"para o comando testing. Aqui está um exemplo:

Acredite ou não, mas essas condições estão produzindo o mesmo resultado :

if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...

TL; DR; sempre compare com strings ou números

Para deixar isso claro para os futuros leitores, eu recomendaria sempre usar aspas truee false:

FAZ

if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...

NÃO

if [ ... ]; then ...  # Always use double square brackets in bash!
if [[ "${var}" ]]; then ...  # This is not as clear or searchable as -n
if [[ "${var}" != true ]]; then ...  # Creates impression of Booleans
if [[ "${var}" -eq "true" ]]; then ...  # `-eq` is for numbers and doesn't read as easy as `==`

Talvez

if [[ "${var}" != "true" ]]; then ...  # Creates impression of Booleans. It can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".
Hubert Grzeskowiak
fonte
Eu prefiro usar Te Fdeixar claro que esses não são valores booleanos reais.
Php # 16/18
1
Não concordo com "sempre use colchetes duplos no bash". De fato, em quase todos os scripts que escrevi, estou usando colchetes simples, exceto quando preciso fazer a correspondência de padrões. Eu acho que se deve entender a diferença entre [(ie test) ee [[usar a que é adequada para sua necessidade.
Weijun Zhou
@WeijunZhou mente em quais casos os colchetes únicos são melhores?
Hubert Grzeskowiak
É mais um gosto pessoal, acho que é ousado demais dizer "Sempre use colchetes duplos no bash". Mas existem alguns casos extremos que eu usei. Parênteses simples permitem especificar o teste em uma var. Como um exemplo simplificado, considereif ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
Weijun Zhou
@WeijunZhou Seu exemplo é um forte argumento contra colchetes simples. Isso torna o código muito mais difícil de entender e abre a janela para erros. Os colchetes duplos são mais rigorosos e incentivam um código mais limpo.
Hubert Grzeskowiak
18

Há muito tempo, quando tudo o que tínhamos era sh, os booleanos eram manipulados, contando com uma convenção do testprograma em que testretornava um status de saída falso, se executado sem argumentos.

Isso permite pensar em uma variável que não está definida como falsa e a variável definida como qualquer valor como verdadeira. Hoje, testé um componente interno do Bash e é comumente conhecido por seu alias de um caractere [(ou um executável para usar em conchas sem ele, como observa o dolmen):

FLAG="up or <set>"

if [ "$FLAG" ] ; then
    echo 'Is true'
else
    echo 'Is false'
fi

# Unset FLAG
#    also works
FLAG=

if [ "$FLAG" ] ; then
    echo 'Continues true'
else
    echo 'Turned false'
fi

Por causa das convenções de citação, os criadores de scripts preferem usar o comando composto [[que imita test, mas possui uma sintaxe melhor: variáveis ​​com espaços não precisam ser citadas; pode-se usar &&e ||como operadores lógicos com precedência estranha, e não há limitações de POSIX no número de termos.

Por exemplo, para determinar se FLAG está definido e COUNT é um número maior que 1:

FLAG="u p"
COUNT=3

if [[ $FLAG  && $COUNT -gt '1' ]] ; then
    echo 'Flag up, count bigger than 1'
else
    echo 'Nope'
fi

Esse material pode ficar confuso quando são necessários espaços, cadeias de comprimento zero e variáveis ​​nulas e também quando seu script precisa trabalhar com vários shells.

Hbar
fonte
3
[não é apenas um apelido por dentro bash. Esse alias também existe como um arquivo binário (ou como um link apontando para) e pode ser usado com o bare sh. Verifique ls -l /usr/bin/\[. Com bash/ zshvocê deve usar [[esse é um verdadeiro interno puro e é muito mais poderoso.
Dolmen
1
@dolmen [e testtambém é um COMANDO BUILTIN do Bash SHELL, de acordo com a página de manual do Bash, portanto, não deve haver problema no desempenho. A mesma coisa com, por exemplo, Dash. (/ bin / sh pode ser apenas um link simbólico para / bin / dash). Para usar o executável, você deve usar o caminho completo, ie /usr/bin/\[.
213 jar Jar
12

Como posso declarar e usar variáveis ​​booleanas em um script de shell?

Ao contrário de muitas outras linguagens de programação, o Bash não segrega suas variáveis ​​por "tipo". [1]

Então a resposta é bem clara. Não há nenhuma variável booleana no Bash.

Contudo:

Usando uma declaração declare, podemos limitar a atribuição de valor a variáveis. [2]

#!/bin/bash
declare -ir BOOL=(0 1) # Remember BOOL can't be unset till this shell terminates
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}

# Same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"

A ropção in declaree readonlyé usada para declarar explicitamente que as variáveis ​​são somente leitura . Espero que o objetivo seja claro.

sjsam
fonte
1
Por que você simplesmente não faz declare -ir false=0 true=1? Qual é a vantagem de usar uma matriz?
Benjamin W.
@BenjaminW. Eu só queria mencionar sobre a ropção e readonlycomando. Gostaria de fazê-lo da maneira que você sugeriu em meus scripts
sjsam
talvez eu tenha perdido alguma coisa, mas por que verdadeiro e falso não declarados dessa maneira usam o cifrão? $ true $ false
qodeninja
Literalmente apenas copiando minha resposta e tornando-a pior.
Perguntas Quolonel
@QuolonelQuestions As variáveis ​​bash não são digitadas , portanto, não há sentido em dizer declare and use boolean variables. Nós poderíamos apenas, de mais de uma maneira, imitar / supor que uma variável tenha um tipo . Não vi isso mencionado em nenhum lugar da sua resposta.
sjsam
10

Em vez de fingir um booleano e deixar uma armadilha para futuros leitores, por que não usar um valor melhor do que verdadeiro e falso?

Por exemplo:

build_state=success
if something-horrible; then
  build_state=failed
fi

if [[ "$build_state" == success ]]; then
  echo go home; you are done
else
  echo your head is on fire; run around in circles
fi
Pyrolistical
fonte
por que não números inteiros?
31517 philip4
3
@ Blauhirn porque números inteiros são usados ​​de maneira diferente dependendo dos idiomas. Em algumas línguas, 0coage para falsee 1para true. No que diz respeito aos códigos de saída do programa (que o bash usa historicamente), é 0para resultado positivo ou truee todo o resto é negativo / erro ou false.
Hubert Grzeskowiak 3/11
7

POSIX (Interface de sistema operacional portátil)

Sinto falta aqui do ponto chave, que é a portabilidade. É por isso que meu cabeçalho possui o POSIX em si.

Basicamente, todas as respostas votadas estão corretas, com a exceção de serem específicas do Bash em demasia.

Basicamente, desejo apenas adicionar mais informações sobre portabilidade.


  1. [e ]colchetes como em [ "$var" = true ]não são necessários, e você pode omiti-los e usar o testcomando diretamente:

    test "$var" = true && yourCodeIfTrue || yourCodeIfFalse

    Nota importante: não recomendo mais isso , pois está sendo preterido lentamente e mais difícil combinar várias instruções.

  2. Imagine o que essas palavras truee falsedizer para o shell, teste você mesmo:

    echo $(( true ))
    0
    echo $(( false ))
    1

    Mas usando aspas:

    echo $(( "true" ))
    bash: "true": syntax error: operand expected (error token is ""true"")
    sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""

    O mesmo vale para:

    echo $(( "false" ))

    O shell não pode interpretá-lo além de uma string. Espero que você esteja tendo a idéia de como é bom usar palavras-chave adequadas sem aspas .

    Mas ninguém disse isso em respostas anteriores.

  3. O que isto significa? Bem, várias coisas.

    • Você deve se acostumar com as palavras-chave booleanas que são tratadas como números, ou seja, true= 0e false= 1, lembre-se de que todos os valores diferentes de zero são tratados como números false.

    • Como eles são tratados como números, você também deve tratá-los assim, ou seja, se você definir a variável, diga:

      var_bool=true
      echo "$var_bool"
       true

      você pode criar um valor oposto com:

      var_bool=$(( 1 - $var_bool ))  # same as $(( ! $var_bool ))
      echo "$var_bool"
      1

    Como você pode ver por si mesmo, o shell imprime truestring pela primeira vez em que você o usa, mas desde então tudo funciona através do número que 0representa trueou 1representa false, respectivamente.


Finalmente, o que você deve fazer com todas essas informações

  • Primeiro, um bom hábito seria atribuir em 0vez de true; 1em vez de false.

  • O segundo bom hábito seria testar se a variável é / não é igual a zero:

    if [ "$var_bool" -eq 0 ]; then
         yourCodeIfTrue
    else
         yourCodeIfFalse
    fi
LinuxSecurityFreak
fonte
6

Com relação à sintaxe, esta é uma metodologia simples que eu uso (por exemplo) para gerenciar de forma consistente e saudável a lógica booleana:

# Tests
var=
var=''
var=""
var=0
var=1
var="abc"
var=abc

if [[ -n "${var}" ]] ; then
    echo 'true'
fi
if [[ -z "${var}" ]] ; then
    echo 'false'
fi

# Results
# var=        # false
# var=''      # false
# var=""      # false
# var=0       # true
# var=1       # true
# var="abc"   # true
# var=abc     # true

Se a variável nunca for declarada, a resposta é: # false

Portanto, uma maneira simples de definir uma variável como verdadeira (usando essa metodologia de sintaxe) seria var=1,; inversamente var=''.

Referência:

-n = True se o comprimento da string var for diferente de zero.

-z = True se o comprimento da string var for zero.

Eric P
fonte
5

Em muitas linguagens de programação, o tipo booleano é, ou é implementado como, um subtipo de número inteiro, em que truese comporta 1e falsese comporta como 0:

Matematicamente , a álgebra booleana se assemelha ao módulo aritmético inteiro 2. Portanto, se um idioma não fornecer o tipo booleano nativo, a solução mais natural e eficiente é usar números inteiros. Isso funciona com quase qualquer idioma. Por exemplo, no Bash, você pode:

# val=1; ((val)) && echo "true" || echo "false"
true
# val=0; ((val)) && echo "true" || echo "false"
false

festança do homem :

((expressão))

A expressão é avaliada de acordo com as regras descritas abaixo em AVALIAÇÃO ARITMÉTICA. Se o valor da expressão for diferente de zero, o status de retorno será 0; caso contrário, o status de retorno é 1. Isso é exatamente equivalente a deixar "expressão".

Cyker
fonte
5

Bill Parker está sendo rejeitado , porque suas definições são revertidas da convenção de código normal. Normalmente, true é definido como 0 e false é definido como diferente de zero. 1 funcionará para false, assim como 9999 e -1. O mesmo com os valores de retorno da função - 0 é sucesso e qualquer coisa diferente de zero é falha. Desculpe, ainda não tenho credibilidade nas ruas para votar ou responder diretamente a ele.

Bash recomenda o uso de colchetes agora como um hábito, em vez de colchetes simples, e o link que Mike Holt deu explica as diferenças de como eles funcionam. 7.3 Outros operadores de comparação

Por um lado, -eqé um operador numérico, portanto, ter o código

#**** NOTE *** This gives error message *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

emitirá uma instrução de erro, esperando uma expressão inteira. Isso se aplica a qualquer parâmetro, pois também não é um valor inteiro. No entanto, se colocarmos colchetes duplos em torno dele, ele não emitirá uma declaração de erro, mas produzirá um valor errado (bem, em 50% das permutações possíveis). Ele avaliará como [[0-eq verdadeiro]] = sucesso, mas também para [[0-eq falso]] = sucesso, o que está errado (hmmm .... e quanto a esse valor embutido ser um valor numérico?).

#**** NOTE *** This gives wrong output *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then

Existem outras permutações do condicional que também produzirão resultados errados. Basicamente, qualquer coisa (que não seja a condição de erro listada acima) que define uma variável para um valor numérico e a compara com um verdadeiro / falso embutido ou define uma variável para um verdadeiro / falso embutido e a compara com um valor numérico. Além disso, qualquer coisa que defina uma variável como um verdadeiro / falso interno e faça uma comparação usando -eq. Portanto, evite -eqcomparações booleanas e evite usar valores numéricos para comparações booleanas. Aqui está um resumo das permutações que fornecerão resultados inválidos:

# With variable set as an integer and evaluating to true/false
# *** This will issue error warning and not run: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

# With variable set as an integer and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" == true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then


# With variable set as an true/false builtin and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = 0 ]; then
#
if [[ "${The_world_is_flat}" = 0 ]]; then
#
if [ "${The_world_is_flat}" == 0 ]; then
#
if [[ "${The_world_is_flat}" == 0 ]]; then

Então, agora para o que funciona. Use builtins verdadeiro / falso para sua comparação e suas avaliações (como observou Mike Hunt, não as coloque entre aspas). Em seguida, use um ou o sinal de igual simples ou duplo (= ou ==) e colchetes simples ou duplos ([] ou [[]]). Pessoalmente, gosto do sinal de igual duplo, porque me lembra comparações lógicas em outras linguagens de programação e aspas duplas apenas porque gosto de digitar. Então, estes funcionam:

# With variable set as an integer and evaluating to true/false
# *** These statements will work properly: *****
#
The_world_is_flat=true/false;
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then

Aí está.

Randyman99
fonte
2
Os true/ falsebuilt-ins não são usados ​​aqui (ignore o que o destaque da sintaxe de alguns editores pode implicar), especialmente nos […]casos em que você pode pensar nele como uma string simples aqui (que é fornecida como parâmetro para o [comando).
Php 25/16
Você tem agora.
Peter Mortensen
4

Minhas descobertas e sugestões diferem um pouco das outras postagens. Eu descobri que podia usar "booleanos" basicamente como se fosse em qualquer linguagem "normal", sem o "salto de arco" sugerido ...

Não há necessidade []ou comparações explícitas de strings ... Tentei várias distribuições Linux. Testei Bash, Dash e BusyBox . Os resultados sempre foram os mesmos. Não sei ao certo o que estão falando nas principais postagens votadas originais. Talvez os tempos tenham mudado e isso é tudo o que há para isso?

Se você definir uma variável como true, ela será avaliada posteriormente como "afirmativa" dentro de uma condicional. Defina como falsee avalia como "negativo". Muito simples! A única ressalva é que uma variável indefinida também é avaliada como verdadeira ! Seria bom se fizesse o contrário (como faria na maioria dos idiomas), mas esse é o truque - você só precisa inicializar explicitamente seus booleanos para true ou false .

Por que funciona dessa maneira? Essa resposta é dupla. A) verdadeiro / falso em um shell realmente significa "sem erro" vs "erro" (ou seja, 0 vs qualquer outra coisa). B) verdadeiro / falso não são valores - mas declarações em scripts de shell! Em relação ao segundo ponto, executar trueou falseem uma linha por si só define o valor de retorno do bloco em que você está nesse valor, ou seja, falseé uma declaração de "erro encontrado", onde verdadeiro "limpa" isso. Usá-lo com uma atribuição a uma variável "retorna" para a variável. Uma variável indefinida é avaliada como trueem uma condicional porque isso representa igualmente 0 ou "nenhum erro encontrado".

Veja o exemplo de linhas Bash e resultados abaixo. Teste você mesmo se quiser confirmar ...

#!/bin/sh

# Not yet defined...
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=true
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=false
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

Rendimentos

when set to
it evaluates to true
when set to true
it evaluates to true
when set to false
it evaluates to false
BuvinJ
fonte
1

Aqui está um exemplo simples que funciona para mim:

temp1=true
temp2=false

if [ "$temp1" = true ] || [ "$temp2" = true ]
then
    echo "Do something." 
else
    echo "Do something else."
fi
Harsimranjit Singh Kler
fonte
1

Aqui está uma implementação de uma mão curta if true.

# Function to test if a variable is set to "true"
_if () {
    [ "${1}" == "true" ] && return 0
    [ "${1}" == "True" ] && return 0
    [ "${1}" == "Yes" ] && return 0
    return 1
}

Exemplo 1

my_boolean=true

_if ${my_boolean} && {
    echo "True Is True"
} || {
    echo "False Is False"
}

Exemplo 2

my_boolean=false
! _if ${my_boolean} && echo "Not True is True"
llundin
fonte
Sim, a decomposição funcional é subestimada.
Peter Mortensen
1

Achei as respostas existentes confusas.

Pessoalmente, eu só quero ter algo que pareça e funcione como C.

Este trecho funciona muitas vezes ao dia na produção:

snapshotEvents=true

if ($snapshotEvents)
then
    # Do stuff if true
fi

e para manter todos felizes, testei:

snapshotEvents=false

if !($snapshotEvents)
then
    # Do stuff if false
fi

O que também funcionou bem.

O $snapshotEventsavalia o conteúdo do valor da variável. Então você precisa do $.

Você realmente não precisa dos parênteses, eu apenas os acho úteis.

vai
fonte
2
Onde você remove os parênteses, esta é exatamente a resposta original do @ miku na parte superior.
Dolmen
1
Sem parênteses, a expressão não avalia.
será
@ sim sim. Você não precisa do () s.
precisa saber é
1
@Blauhirn ... Olá, eu baseei meus comentários em experimentos com o GNU Bash em um PC Linux Mint / Ubuntu. Você provavelmente está certo na teoria - () s não são necessários. Minha única resposta, é experimentá-lo, parece depender da versão do Bash, da expressão ou contexto real e tal.
será
1

Aqui está uma melhoria na resposta original do miku que aborda as preocupações de Dennis Williamson sobre o caso em que a variável não está definida:

the_world_is_flat=true

if ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

E para testar se a variável é false:

if ! ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

Sobre outros casos com um conteúdo desagradável na variável, esse é um problema com qualquer entrada externa alimentada em um programa.

Qualquer entrada externa deve ser validada antes de confiar nela. Mas essa validação deve ser feita apenas uma vez, quando essa entrada é recebida.

Ele não precisa afetar o desempenho do programa, fazendo isso em todos os usos da variável, como sugere Dennis Williamson .

dolmen
fonte
1

Você pode usar shFlags .

Oferece a opção de definir: DEFINE_bool

Exemplo:

DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");

Na linha de comando, você pode definir:

sh script.sh --bigmenu
sh script.sh --nobigmenu # False
gogasca
fonte
GFlags não faz sentido nesta resposta - é uma biblioteca C ++. Ele não pode ser usado diretamente em scripts de shell.
Jonathan Cross
Resposta atualizada para shFlags, que é uma porta do GFlags para o shell.
gogasca
0

Este é um teste de velocidade sobre diferentes maneiras de testar os valores "booleanos" no Bash:

#!/bin/bash
rounds=100000

b=true # For true; b=false for false
type -a true
time for i in $(seq $rounds); do command $b; done
time for i in $(seq $rounds); do $b; done
time for i in $(seq $rounds); do [ "$b" == true ]; done
time for i in $(seq $rounds); do test "$b" == true; done
time for i in $(seq $rounds); do [[ $b == true ]]; done

b=x; # Or any non-null string for true; b='' for false
time for i in $(seq $rounds); do [ "$b" ]; done
time for i in $(seq $rounds); do [[ $b ]]; done

b=1 # Or any non-zero integer for true; b=0 for false
time for i in $(seq $rounds); do ((b)); done

Seria imprimir algo como

true is a shell builtin
true is /bin/true

real    0m0,815s
user    0m0,767s
sys     0m0,029s

real    0m0,562s
user    0m0,509s
sys     0m0,022s

real    0m0,829s
user    0m0,782s
sys     0m0,008s

real    0m0,782s
user    0m0,730s
sys     0m0,015s

real    0m0,402s
user    0m0,391s
sys     0m0,006s

real    0m0,668s
user    0m0,633s
sys     0m0,008s

real    0m0,344s
user    0m0,311s
sys     0m0,016s

real    0m0,367s
user    0m0,347s
sys     0m0,017s
jarno
fonte
-2

Alternativa - use uma função

is_ok(){ :;}
is_ok(){ return 1;}
is_ok && echo "It's OK" || echo "Something's wrong"

Definir a função é menos intuitivo, mas verificar seu valor de retorno é muito fácil.

johnraff
fonte
1
Esta não é uma variável que você pode testar, mas uma função constante
Jarno
@jarno Testar o valor de retorno de uma função é diferente de testar uma variável, para os propósitos de um script?
johnraff
Bem, a questão é sobre variáveis.
Jar19 /
Verdade, embora o uso em um script de shell seja o mesmo.
21419 Johnraff
-2

Bash realmente confunde a questão com os gostos de [, [[, ((, $((, etc.

Todos pisando nos espaços de código uns dos outros. Eu acho que isso é principalmente histórico, onde Bash tinha que fingir estar shocasionalmente.

Na maioria das vezes, eu posso escolher um método e seguir com ele. Nesse caso, tenho a tendência de declarar (de preferência em um arquivo de biblioteca comum com o qual posso incluir .meus scripts).

TRUE=1; FALSE=0

Posso então usar o ((... ))operador aritmético para testar dessa forma.

testvar=$FALSE

if [[ -d ${does_directory_exist} ]]
then
    testvar=$TRUE;
fi

if (( testvar == TRUE )); then
    # Do stuff because the directory does exist
fi
  1. Você precisa ser disciplinado. Você testvardeve estar definido como $TRUEou $FALSEsempre.

  2. Nos ((... ))comparadores, você não precisa do anterior $, o que o torna mais legível.

  3. Eu posso usar ((... ))porque $TRUE=1e $FALSE=0, ou seja, valores numéricos.

  4. A desvantagem é ter que usar um $ocasionalmente:

    testvar=$TRUE

    o que não é tão bonito.

Não é uma solução perfeita, mas abrange todos os casos que eu preciso desse teste.

Bill Parker
fonte
2
Você deve declarar suas constantes somente leitura. Além disso, sempre use colchetes ao usar variáveis. É uma convenção que todos devem seguir o IMHO. A grande desvantagem desta solução é que você não pode misturar a expressão algébrica com sinalizadores de teste ou comparações de cadeias.
Hubert Grzeskowiak