Em um script bash, usando o condicional "ou" em uma instrução "se"

129

Esta pergunta é uma espécie de sequela da minha pergunta anterior . Os usuários deste site gentilmente me ajudaram a determinar como escrever um forloop bash que itera sobre os valores das strings. Por exemplo, suponha que uma variável de controle de loop fnameitere sobre as strings "a.txt" "b.txt" "c.txt". Eu gostaria de echo"sim!" quando fnametem o valor "a.txt"ou "c.txt"e echo"não!" de outra forma. Eu tentei o seguinte script shell bash:

#!/bin/bash

for fname in "a.txt" "b.txt" "c.txt"
do
 echo $fname
 if [ "$fname" = "a.txt" ] | [ "$fname" = "c.txt" ]; then
 echo "yes!"
else
 echo "no!"
fi
done

Eu obtenho a saída:

a.txt

não!

b.txt

não!

c.txt

sim!

Por que a ifdeclaração aparentemente produz verdade quando fnametem o valor "a.txt"? Eu usei |incorretamente?

Andrew
fonte
3
No bash, 'ou' operador é '||' (Estilo C).
Marius Cotofana 08/09/12
3
Você também pode usar -odentro do mesmo [ ].
Thor
6
@Thor eu prefiro ||e separar [ ]mais -opara a portabilidade, simplesmente porque [não é garantido para suportar mais de 4 argumentos. Claro, se a língua-alvo é bash, ninguém deve estar usando [de qualquer maneira, porque bash's [[é superior em muitas maneiras.
jw013
2
@ jw013 Obrigado. Isso significa que eu deveria estar usando if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]]e não if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]?
Andrew
5
@ Andrew Isso está correto, se você estiver declarando o shebang como bash, como você já está fazendo. Uma vantagem [[disso é que ele não faz a divisão de palavras (caso especial), portanto [[ $unquoted_var = string ]]é seguro.
Jw013

Respostas:

229

Se você quiser dizer, ORuse double pipe ( ||).

if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]

(O código OP original usado |era simplesmente canalizar a saída do lado esquerdo para o lado direito, da mesma forma que qualquer tubo comum funciona.)

bahamat
fonte
4
Além disso, ||não executa uma lógica padrão "OR" - ele provoca um curto-circuito e o segundo comando é executado apenas se o primeiro falhar.
holdenweb
13
@holdenweb Tenho certeza de que a maioria dos idiomas otimizados modernos funciona da mesma maneira. Não é necessário gastar ciclos de CPU avaliando a segunda condição ORse a primeira condição é verdadeira.
bahamat
11
Eu pensei que o bash gostava, ==mas depois de ver essa resposta, decidi procurar. Aparentemente, "pode ​​ser usado, mas não é padrão". Eu pensei em colocar isso aqui para os outros se o seu curioso: stackoverflow.com/a/2237103
harperville
Isto é o que a testpágina de manual também recomenda
cdosborn
2
Você também pode usar testes de colchetes duplos - if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]](se desejar ou precisar da funcionalidade extra associada [[ ]]).
HankCa