Estou aprendendo sobre estruturas de tomada de decisão e me deparei com estes códigos:
if [ -f ./myfile ]
then
cat ./myfile
else
cat /home/user/myfile
fi
[ -f ./myfile ] &&
cat ./myfile ||
cat /home/user/myfile
Ambos se comportam da mesma maneira. Existem vantagens em usar uma maneira da outra?
shell-script
syntax
control-flow
Subhaa Chandar
fonte
fonte
Respostas:
Não, construções
if A; then B; else C; fi
e nãoA && B || C
são equivalentes .Com
if A; then B; else C; fi
, o comandoA
é sempre avaliado e executado (pelo menos é feita uma tentativa de executá-lo) e, em seguida, um comandoB
ou comandoC
é avaliado e executado.Com
A && B || C
, que é o mesmo para os comandosA
eB
, mas diferente paraC
: comandoC
é avaliado e executado se querA
falhar ouB
falhar.No seu exemplo, suponha que você
chmod u-r ./myfile
, apesar de ser[ -f ./myfile ]
bem-sucedido,cat /home/user/myfile
Meu conselho: use
A && B
ou oA || B
que quiser, isso continua fácil de ler e entender e não há armadilha. Mas se você quer dizer se ... então ... mais ... então useif A; then B; else C; fi
.fonte
A maioria das pessoas acham que é mais fácil compreender a
if
...then
...else
...fi
formulário.Para o
a && b || c
, você precisa ter certeza de queb
retorna verdadeiro. Isso é uma causa de erros sutis e é uma boa razão para evitar esse estilo. Se b não retornar true, eles não serão os mesmos.Para testes e ações muito curtos que não possuem uma cláusula else, o comprimento reduzido é atraente, por exemplo
&&
e||
sãoshort circuiting operators
, assim que o resultado é conhecido mais testes desnecessários são ignorados.a && b || c
está agrupado como(a && b) || c
. Primeiroa
é executado. Sefails
for definido como não retornando um status de saída 0, o grupo(a && b)
é conhecidofail
eb
não precisa ser executado. O||
não sabe o resultado da expressão, portanto, precisa executarc
. Sea
for bem-sucedido (retorna zero), o&&
operador ainda não sabe o resultado,a && b
portanto, precisa executarb
para descobrir. Seb
fora && b
bem- sucedido, obtém êxito e||
sabe que o resultado geral é bem-sucedido, portanto, não precisa ser executadoc
. Seb
falhar, então||
ainda não sabe o valor da expressão, é necessário executarc
.fonte
O operador && executa o próximo comando se o comando anterior teve uma execução bem-sucedida (código de saída retornado ($?) 0 = true lógico).
No formulário
A && B || C
, o comando (ou condição) A é avaliado e, se A retornar verdadeiro (êxito, código de saída 0), o comando B será executado. Se A falhar (retornará um código de saída falso diferente de 0) e / ou B falhar (retornar falso ), o comando C será executado.Além disso, o
&&
operador é usado como um E nas verificações de condição e o operador||
trabalha como OU nas verificações de condição.Dependendo do que você deseja fazer com seu script, o formulário
A && B || C
pode ser usado para verificações de condições como o seu exemplo ou para encadear comandos e garantir que uma série de comandos seja executada se os comandos anteriores tiverem um código de saída 0 bem-sucedido .É por isso que é comum ver comandos como:
do_something && do_something_else_that_depended_on_something
.Exemplos:
apt-get update && apt-get upgrade
se a atualização falhar, a atualização não será executada (faz sentido no mundo real ...).mkdir test && echo "Something" > test/file
A peça
echo "Something"
será executada apenas semkdir test
for bem-sucedida e a operação retornar o código de saída 0 ../configure --prefix=/usr && make && sudo make install
Geralmente encontrado na compilação de tarefas para encadear comandos dependentes necessários.
Se você tentar implementar as "cadeias" acima com o if - then - else , precisará de muito mais comandos e verificações (e, portanto, mais código para escrever - mais coisas dar errado) para uma tarefa simples.
Além disso, lembre-se de que comandos encadeados com && e || são lidos pelo shell da esquerda para a direita. Pode ser necessário agrupar comandos e verificações de condição com colchetes para depender da próxima etapa da saída bem-sucedida de alguns comandos anteriores. Por exemplo, veja isto:
Ou um exemplo da vida real:
Lembre-se de que alguns comandos retornam códigos de saída diferentes, dependendo do processo executado, ou retornam códigos diferentes, dependendo de suas ações (por exemplo, comando GNU
diff
, retorna 1 se dois arquivos diferem e 0 se não). Tais comandos precisam ser tratados com cuidado em && e || .Além disso, apenas para ter todo o quebra-cabeça em conjunto, lembre-se da concatenação de comandos usando o
;
operador. Com um formato,A;B;C
todos os comandos serão executados em série, independentemente do código de comandoA
e de saídaB
.fonte
Grande parte da confusão sobre isso pode dever-se à documentação do bash que chama essas listas AND e OR . Embora sejam logicamente semelhantes aos
&&
e||
encontrados entre colchetes, eles funcionam de maneira diferente.Alguns exemplos podem ilustrar isso melhor ...
Se
cmda
sair verdadeiro,cmdb
é executado.Se
cmda
sair falso,cmdb
NÃO é executado, mascmdc
é.Como
cmda
saídas é ignorado.Se
cmdb
sair verdadeiro,cmdc
é executado.Se
cmdb
sair falso,cmdc
NÃO é executado ecmdd
é.Se
cmda
sai verdadeiro,cmdb
é executado, seguido porcmdc
.Se
cmda
sair falso,cmdb
NÃO é executado, mascmdc
é.Hã? Por que é
cmdc
executado?Porque para o intérprete, um ponto-e-vírgula (
;
) e uma nova linha significam exatamente a mesma coisa. Bash vê essa linha de código como ...Para alcançar o que é esperado, precisamos incluir
cmdb; cmdc
chaves entre chaves para torná-las um comando composto (comando de grupo) . O ponto e vírgula de terminação adicional é apenas um requisito da{ ...; }
sintaxe. Então nós temos ...cmda && { cmdb; cmdc; }
Se
cmda
sai verdadeiro,cmdb
é executado, seguido porcmdc
.Se
cmda
saídas falsas, nemcmdb
oucmdc
é executado.A execução continua com a próxima linha.
Uso
As listas de comandos condicionais são mais úteis para retornar o mais rápido possível das funções e, assim, evitar a interpretação e a execução de muitos códigos desnecessários. Entretanto, o retorno de várias funções significa que é preciso ser obsessivo em manter as funções curtas, para que seja mais fácil garantir que todas as condições possíveis sejam cobertas.
Aqui está um exemplo de algum código em execução ...
fonte