Considere duas expressões condicionais expr1
e expr2
, por exemplo, $i -eq $j
e $k -eq $l
. Podemos escrever isso de bash
várias maneiras. Aqui estão duas possibilidades
[[ expr1 || expr2 ]]
[[ expr1 ]] || [[ expr2 ]]
Tenho certeza de que vi recomendações aqui de que o segundo deveria ser preferido, mas não consigo encontrar evidências para apoiar isso.
Aqui está um exemplo de script que parece demonstrar que não há diferença:
for i in 0 1
do
for j in 0 1
do
for k in 0 1
do
for l in 0 1
do
if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yes\t"; else printf "1-no\t"; fi
if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yes\n"; else printf "2-no\n"; fi
done
done
done
done
e saída mostrando que ambas as construções de condição produzem o mesmo resultado:
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-no 2-no
1-no 2-no
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
1-yes 2-yes
Existe algum benefício em usar uma construção sobre a outra?
Para pontos de bônus, a mesma pergunta, mas generalizando para várias condições usando ||
e &&
. Por exemplo [[ expr1 && expr2 || expr3 ]]
,.
[
outest
( não[[
), procure asOB
tags (vinculadas à definição "obsolescente") na especificação POSIX paratest
. Emtest
, existem alguns casos patológicos em que pode ser impossível dizer se(
ou)
pretende ser sintaxe significativo para o comando de teste ou uma string a ser testados, para que as pessoas que ignoram os marcadores obsolescência e usam essa sintaxe pode realmente precisa do otherwise-"x$foo"
prática obsoleta ; com[[
, isso não é um problema.Respostas:
Eu acho que a recomendação que você viu foi para POSIX sh e / ou o
test
comando que funciona como o[
comando, em vez da[[
construção que apareceu no ksh (obrigado Stéphane Chazelas pela dica) e também é usada, por exemplo, no bash, zsh e outros cartuchos.Na maioria dos idiomas, como C, quando uma cláusula já é verdadeira ou falsa, não há necessidade de avaliar as partes restantes, dependendo da operação: se verdadeira não após uma lógica ou segui-la, se falsa não após uma lógica e , etc. Isso obviamente permite, por exemplo, parar quando um ponteiro é NULL e não tentar desreferê-lo na próxima cláusula.
Mas o constructo sh
[ expr1 -o expr2 ]
(incluindo a implementação do bash) não faz isso: ele sempre avalia os dois lados, quando se deseja que apenas expr1 seja avaliado. Isso pode ter sido feito para compatibilidade com atest
implementação do comando. Por outro lado, sh||
e&&
siga o princípio usual: não avaliado se não alterar o resultado.Portanto, a diferença a ser observada seria:
que produz:
Acima, cada um
[
poderia ter sido substituído por/usr/bin/[
um alias para otest
comando, usado antes,[
foi incorporado aos shells.Enquanto as duas próximas construções:
ou
Apenas renderá
true
e deixaráeffect
vazio:||
se comporta corretamente e também[[
corrigiu esse problema.ATUALIZAR:
Como o @ StéphaneChazelas comentou, perdi várias diferenças relacionadas à pergunta inicial. Vou colocar aqui o mais importante (pelo menos para mim): prioridade dos operadores.
Embora o shell não considere precedência:
rendimentos (porque não há precedência e, portanto, primeiro
true || true
é avaliado e depois&& false
):dentro
[[ ]]
do&&
operador tem precedência sobre||
:rendimentos (porque
1 -eq 1 && 1 -eq 0
está agrupado e, portanto, é o segundo membro de||
):pelo menos para ksh , bash , zsh .
O mesmo
[[ ]]
ocorreu com o comportamento aprimorado dos[ ]
operadores lógicos diretos e do shell.fonte
[ x -o y ]
não precisa avaliar os dois lados. Enquanto o GNUtest
ou o[
built-ofbash
do, você descobririastrace zsh -c '[ x -o -f /x ]'
que[
não tenta stat ()/x
. O mesmo commksh
. Mas é verdade que,-o
e-a
estão gravemente danificados, não podem ser usados com segurança e estão obsoletos pelo POSIX.[[...]]
, por dentro ,&&
tem maior precedência do que||
, enquanto por fora eles têm igual precedência. Compareksh -c '[[ x || x && "" ]]'
vssh -c 'true || true && false'
[
/test
utilitário não possui um==
operador. O operador de igualdade é=
(observe que dentro do ksh[[...]]
,=
/==
não são operadores de igualdade, mas que correspondem a padrões).&&
tem precedência sobre||
dentro[[...]]
(ou((...))
), mas não os&&
e||
shell operadores.[[ x || y && z ]]
isx || (y && z)
whilex || y && z
is(x || y) && z
(operadores avaliados da esquerda para a direita sem precedência). Semelhante à forma como*
tem precedência sobre+
(1 + 2 * 3
é1 + (2 * 3)
), mas+
e-
têm a mesma precedência.&&
tem mais de precedência||
, então ele deve estartrue || (true && false)
, em vez de(true || true) && false