Quero representar várias condições como esta:
if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]
then
echo abc;
else
echo efg;
fi
mas quando executo o script, ele mostra
syntax error at line 15: `[' unexpected,
onde a linha 15 é a que mostra se ....
O que há de errado com essa condição? Eu acho que algo está errado com o ()
.
test
([
) e não pelo shell. O shell avalia apenas o status de saída de[
.Respostas:
Técnica clássica (metacaracteres de escape):
Coloquei as referências
$g
entre aspas duplas; Essa é uma boa prática, em geral. Estritamente, os parênteses não são necessários porque a precedência-a
e-o
a corrige mesmo sem eles.Note que o
-a
e-o
operadores são parte da especificação POSIX paratest
, aka[
, principalmente para compatibilidade com versões anteriores (desde que eles eram uma partetest
na 7ª Edição UNIX, por exemplo), mas eles são explicitamente marcados como 'obsoletos' por POSIX. O Bash (consulte expressões condicionais ) parece antecipar os significados clássico e POSIX para-a
e-o
com seus próprios operadores alternativos que recebem argumentos.Com algum cuidado, você pode usar o
[[
operador mais moderno , mas lembre-se de que as versões no Bash e Korn Shell (por exemplo) não precisam ser idênticas.Exemplo de execução, usando o Bash 3.2.57 no Mac OS X:
Você não precisa citar as variáveis
[[
como faz[
porque não é um comando separado da mesma maneira que[
é.Eu teria pensado assim. No entanto, existe outra alternativa, a saber:
De fato, se você ler as diretrizes do 'shell portátil' para a
autoconf
ferramenta ou pacotes relacionados, essa notação - usando '||
' e '&&
' - é o que eles recomendam. Suponho que você poderia ir tão longe quanto:Onde as ações são tão triviais quanto ecoantes, isso não é ruim. Quando o bloco de ação a ser repetido possui várias linhas, a repetição é muito dolorosa e uma das versões anteriores é preferível - ou você precisa agrupar as ações em uma função que é invocada nos diferentes
then
blocos.fonte
-a
na verdade têm maior precedência do que-o
(diferente do shell&&
e||
no shell - no entanto, dentro debash
[[ ... ]]
condicionais ,&&
também tem maior precedência do que||
). Se você queria evitar-a
e-o
de robustez máxima e portabilidade - que a página homem POSIX si sugere - você também pode usar subshells para o agrupamento:if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
if test "$g" -eq 1 -a "$c" = "123" || test "$g" -eq 2 -a "$c" = "456"; then ...
&&
ou||
também é preferível, pois se comporta mais como condicionais em outros idiomas e permite que você provoque um curto-circuito. Por exemplo:if [ -n "${check_inodes}" ] && [ "$(stat -f %i "/foo/bar")" = "$(stat -f %i "/foo/baz")" ]
. Fazendo dessa maneira, secheck_inodes
estiver vazio, você evita duas chamadas parastat
, enquanto uma condição de teste maior e complexa deve processar todos os argumentos antes da execução (o que também pode levar a erros se você esquecer esse comportamento).No Bash:
fonte
bash
. Como um aparte: neste caso em particular, os parênteses nem são necessários, porque condicionais internos têm realmente maior precedência do que - diferentemente de fora desses condicionais.[[ ... ]]
&&
||
if
/else
e ter o código entrethen
efi
colocar em uma função para evitar repeti-la. Em casos muito simples, você pode usar umacase
declaração com;&
explicação (no Bash 4).Usar
/bin/bash
o seguinte funcionará:fonte
Cuidado se você tiver espaços em suas variáveis de string e verificar a existência. Não deixe de citá-los corretamente.
fonte
fonte
{ ;}
poderia ser usado em seu lugar.No bash para comparação de cadeias, você pode usar a seguinte técnica.
Exemplo:
fonte
fonte
você também pode encadear mais de 2 condições:
fonte