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 ]
true
efalse
no contexto da maioria dos trechos abaixo, são apenas strings simples, não obash 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)true
. Acontece que a resposta original de Miku realmente chamou otrue
built-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.[ true ] && echo yes, true is true
e (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.variable=something
como verdadeiro, se não definido ,variable=
isso seria falso[[ $variable ]] && echo true || echo false
e reverso[[ ! $variable ]] && echo false || echo true
Respostas:
Resposta Revisada (12 de fevereiro de 2014)
Resposta original
Advertências: https://stackoverflow.com/a/21210966/89391
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
true
em 2 de junho de 2010 se aplica apenas à resposta original, não à revisada.fonte
if
instrução está executando o conteúdo da variável que é o Bash embutidotrue
. Qualquer comando poderia ser definido como o valor da variável e seu valor de saída seria avaliado.&&
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)TL; DR
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.
Nos seguintes casos 2 , essa condição será avaliada como verdadeira e executará o comando aninhado.
Normalmente, você deseja que sua condição seja avaliada como verdadeira apenas quando sua variável "Boolean",
var
neste 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:
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.
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 usartest
ou 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.
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é
man woman
, ainda seria considerado um comando válido, mesmo que não exista essa página de manual.fonte
==
com[
outest
não é portátil. Considerando a portabilidade é a única vantagem[
/test
superação[[
, permaneça com=
.Parece haver algum mal-entendido aqui sobre o Bash embutido
true
e, 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 dotrue
comando. Nesse caso,true
nada mais é do que uma simples cadeia de caracteres etrue
nunca é 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:
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 tokentrue
. É 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:
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:
$the_world_is_flat
para a sequência"true"
."true"
como um comando.true
comando (embutido ou/bin/true
, dependendo da versão do Bash).true
comando (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.if
da instruçãothen
Suportes:
$the_world_is_flat
para a sequência"true"
.string1 = string2
. O=
operador é o operador de comparação de strings do bash . Assim..."true"
e"true"
.if
da instruçãothen
.O código sem colchetes funciona, porque o
true
comando 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 literaltrue
no 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:
Este código apenas imprime "Boa tentativa". O comando reboot não é chamado.
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
==
, comovar=="foo"
(bem, tecnicamente, você pode fazer isso, mas o valor devar
será"=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==
).fonte
$the_world_is_flat && echo "you are in flatland!"
true
construí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.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 debash
cola 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 ?true
, mas geralmente não como algo para comparar uma variável, uma vez que o realtrue
não tem valor em si. Tudo o que faz é definir o status de saída para0
, indicando sucesso. Vale a pena notar que é essencialmente equivalente ao chamado "comando nulo", ou:
. Quanto a usar0
e1
, é 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 tiverflag=0
, eu posso fazer #if (( flag )); then ...
Use expressões aritméticas.
Resultado:
fonte
!
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.(())
expande variáveis recursivamente, o que eu não esperava.foo=bar; bar=baz; ((foo)) && echo echo
imprime nada, mas é verdade combaz=1
. Assim, você pode apoiarfoo=true
efoo=false
também 0 ou 1 fazendotrue=1
.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
true
oufalse
no Bash, é uma string ou um comando / builtin que é usado apenas para o código de saída.Essa sintaxe ...
é essencialmente ...
A condição é verdadeira sempre que o comando retorna o código de saída 0.
true
Efalse
sã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:
Ao usar colchetes ou o
test
comando, 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 ...corresponde a
e o
COMMAND
aqui é[[ 1 == 1 ]]
A
if..then..fi
construção é apenas açúcar sintático. Você sempre pode apenas executar os comandos separados por um e comercial duplo para o mesmo efeito:Ao usar
true
efalse
nessas 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 :
TL; DR; sempre compare com strings ou números
Para deixar isso claro para os futuros leitores, eu recomendaria sempre usar aspas
true
efalse
:FAZ
NÃO
Talvez
fonte
T
eF
deixar claro que esses não são valores booleanos reais.[
(ietest
) ee[[
usar a que é adequada para sua necessidade.if ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
Há muito tempo, quando tudo o que tínhamos era
sh
, os booleanos eram manipulados, contando com uma convenção dotest
programa em quetest
retornava 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):Por causa das convenções de citação, os criadores de scripts preferem usar o comando composto
[[
que imitatest
, 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:
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.
fonte
[
não é apenas um apelido por dentrobash
. Esse alias também existe como um arquivo binário (ou como um link apontando para) e pode ser usado com o baresh
. Verifiquels -l /usr/bin/\[
. Combash
/zsh
você deve usar[[
esse é um verdadeiro interno puro e é muito mais poderoso.[
etest
també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/\[
.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]
A
r
opção indeclare
ereadonly
é usada para declarar explicitamente que as variáveis são somente leitura . Espero que o objetivo seja claro.fonte
declare -ir false=0 true=1
? Qual é a vantagem de usar uma matriz?r
opção ereadonly
comando. Gostaria de fazê-lo da maneira que você sugeriu em meus scriptsdeclare 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.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:
fonte
0
coage parafalse
e1
paratrue
. No que diz respeito aos códigos de saída do programa (que o bash usa historicamente), é0
para resultado positivo outrue
e todo o resto é negativo / erro oufalse
.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.
[
e]
colchetes como em[ "$var" = true ]
não são necessários, e você pode omiti-los e usar otest
comando diretamente:Nota importante: não recomendo mais isso , pois está sendo preterido lentamente e mais difícil combinar várias instruções.
Imagine o que essas palavras
true
efalse
dizer para o shell, teste você mesmo:Mas usando aspas:
O mesmo vale para:
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.
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
=0
efalse
=1
, lembre-se de que todos os valores diferentes de zero são tratados como númerosfalse
.Como eles são tratados como números, você também deve tratá-los assim, ou seja, se você definir a variável, diga:
você pode criar um valor oposto com:
Como você pode ver por si mesmo, o shell imprime
true
string pela primeira vez em que você o usa, mas desde então tudo funciona através do número que0
representatrue
ou1
representafalse
, respectivamente.Finalmente, o que você deve fazer com todas essas informações
Primeiro, um bom hábito seria atribuir em
0
vez detrue
;1
em vez defalse
.O segundo bom hábito seria testar se a variável é / não é igual a zero:
fonte
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:
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
,; inversamentevar=''
.Referência:
-n
= True se o comprimento da string var for diferente de zero.-z
= True se o comprimento da string var for zero.fonte
Em muitas linguagens de programação, o tipo booleano é, ou é implementado como, um subtipo de número inteiro, em que
true
se comporta1
efalse
se comporta como0
:Booleano em C
Booleano em Python
Booleano em Java
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:
festança do homem :
fonte
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ódigoemitirá 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?).
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-eq
comparaçõ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: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:
Aí está.
fonte
true
/false
built-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).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 comofalse
e 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
true
oufalse
em 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 comotrue
em 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 ...
Rendimentos
fonte
Aqui está um exemplo simples que funciona para mim:
fonte
Aqui está uma implementação de uma mão curta
if true
.Exemplo 1
Exemplo 2
fonte
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:
e para manter todos felizes, testei:
O que também funcionou bem.
O
$snapshotEvents
avalia 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.
Testado em: GNU Bash, versão 4.1.11 (2) - lançamento
Guia Bash para Iniciantes , Machtelt Garrels, v1.11, 2008
fonte
()
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.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:
E para testar se a variável é
false
: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 .
fonte
Você pode usar shFlags .
Oferece a opção de definir:
DEFINE_bool
Exemplo:
Na linha de comando, você pode definir:
fonte
Este é um teste de velocidade sobre diferentes maneiras de testar os valores "booleanos" no Bash:
Seria imprimir algo como
fonte
Alternativa - use uma função
Definir a função é menos intuitivo, mas verificar seu valor de retorno é muito fácil.
fonte
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
sh
ocasionalmente.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).Posso então usar o
((
...))
operador aritmético para testar dessa forma.Você precisa ser disciplinado. Você
testvar
deve estar definido como$TRUE
ou$FALSE
sempre.Nos
((
...))
comparadores, você não precisa do anterior$
, o que o torna mais legível.Eu posso usar
((
...))
porque$TRUE=1
e$FALSE=0
, ou seja, valores numéricos.A desvantagem é ter que usar um
$
ocasionalmente:o que não é tão bonito.
Não é uma solução perfeita, mas abrange todos os casos que eu preciso desse teste.
fonte