Parece um bug no seu código, mas podemos reduzi-lo muito bem ...
Se você tivesse realmente escrito sua expressão com [ foo = bar -o foo = car -o foo = jar -o foo = foo ]
, poderia ter sido simplificado para:
echo yes
Esse teste é sempre verdadeiro porque foo = foo
é sempre true, o que, por sua vez, ocorre porque a string literal foo
é sempre a mesma que ela mesma.
Embora você tenha esclarecido que esta sintaxe não apareceu no código que você estava realmente usando, mantive esta seção introdutória, pois é um erro comum fazê-lo, especialmente entre os novatos. Tentar verificar o valor de foo
desta maneira não funciona em nenhum shell estilo Bourne - para examinar o valor de uma variável com [
, você deve executar a expansão de parâmetro com $
(veja abaixo). Esse aspecto específico do problema não é específico do shell; por exemplo, aqui está um teste em 7 shells ao estilo Bourne .
Corrigindo o código original
Talvez, em vez disso, você queira verificar o valor da variável foo
(ou seja, seu conteúdo , em vez de seu nome) em relação a essas sequências. Nesse caso, seu código original se tornaria:
if [ "$foo" = bar -o "$foo" = car -o "$foo" = jar -o "$foo" = foo ]; then
echo yes
fi
Isso pode ser reduzido um pouco com o operador &&
de curto-circuito:
[ "$foo" = bar -o "$foo" = car -o "$foo" = jar -o "$foo" = foo ] && echo yes
Mas ainda é mais longo e mais complicado e repetitivo do que você provavelmente prefere. Então, seguindo em frente ...
Formulários mais curtos via correspondência de padrões
Você pode usar o operador de correspondência de expressão regular integrada do recurso [[
:
[[ $foo =~ ^(bar|car|jar|foo)$ ]] && echo yes
Embora usar case
seja provavelmente a maneira mais comum, [[
com =~
é:
- o mesmo comprimento que um uso compacto de
case
(veja abaixo)
- indiscutivelmente mais fiel à lógica do seu código original, pois ele usa
[[
, que funciona muito como uma expressão de teste.
Então você pode preferir isso. É o método que eu provavelmente usaria, para fazer isso no bash.
Se você quisesse fazer algo assim, mas corresponder usando grep
em vez de [[
com =~
, isso é semelhante:
grep -Eq '^(bar|car|jar|foo)$' <<< "$foo" && echo yes
Ou isto:
grep -Fqe{bar,car,jar,foo} <<< "$foo" && echo yes
Um One-Liner com case
Como Serg diz , pode ser simplificado usando case
em vez de if
e [
. Essa é a maneira clássica e provavelmente a mais comum.
O método em resposta de Serg funciona perfeitamente bem, mas para o código específico que você está refatorando, podemos escrever algo mais simples, usando apenas um padrão para case
. Não há necessidade de ter uma correspondência *)
pega-tudo no final. Se a string não corresponder a nenhum dos padrões, o controle simplesmente passará pela construção da ocorrência e nenhum comando será executado, o que equivale à sua construção if
sem else
.
case $foo in bar|car|jar|foo) echo yes;; esac
Isso faz com que seja curto e simples o suficiente para se ajustar facilmente - e ser legível - em uma única linha (o que parece ser o que você está procurando). Este método também é portável para shells estilo Bourne além de bash.