se condição em várias linhas no shell bash

19

Eu tenho uma função de shell bash que leva um argumento e executar algo nele, se necessário.

do_somthing() {
  if [need to do something on $1]
  then
    do it
    return 0
  else
    return 1
  fi
}

Quero chamar esse método com vários argumentos e verificar se pelo menos um deles foi bem-sucedido.

Eu tentei algo como:

if [ do_something "arg1" ||
     do_something "arg2" ||
     do_something "arg3" ]
then
  echo "OK"
else
  echo "NOT OK"
fi

Qual será a sintaxe correta para isso?
EDITAR
Também - Quero garantir que, mesmo que a primeira condição seja verdadeira, todas as outras condições ainda serão avaliadas.

Obrigado,

Itay
fonte
Eu atualizei minha resposta.
Tectux
Obrigado, você pode fornecer um exemplo?
Itay
11
Adicionei um exemplo de código à minha resposta.
Tectux

Respostas:

7

Execute os comandos primeiro e verifique se pelo menos um deles foi bem-sucedido.

#!/bin/bash

success=0
do_something arg1 && success=1
do_something arg2 && success=1
do_something arg3 && success=1

if ((success)); then
    printf 'Success! At least one of the three commands succeeded\n'
fi
Geirha
fonte
3
Isso é confuso, ficarei feliz se você puder fornecer alguma explicação sobre como as instruções condicionais funcionam no bash ..., do_something retorna 0 após o êxito, mas depois atualizamos o sucesso para 1 ..., if ((success))avalia algo diferente de if success. Estou confuso :)
Itay
2
@ Ittay ((...))é um comando aritmético. Se o resultado interno for diferente de zero, ele retornará verdadeiro (0). Se o resultado interno for 0, ele retornará false (1). "success" é tratado como uma variável que espera conter um número. Veja mywiki.wooledge.org/ArithmeticExpression
geirha
Obrigado, eu acho que a parte que me confundiu é que 0 é verdadeiro e 1 é falso, geralmente, é o oposto :)
Itay
2
@ Sim, pode ser confuso a princípio. O Bash difere das linguagens de uso geral, pois é "baseado em comandos"; não chama funções, não possui classes e métodos, executa comandos e testa o status de saída dos comandos. E é muito mais fácil executar comandos no bash do que linguagens como C, python, java, perl, etc. Os comandos saem com 0 para sinalizar êxito e 1-255 para vários tipos de falhas. (Um comando geralmente só pode ter sucesso em uma maneira, mas não por várias razões diferentes)
geirha
2
Esta solução tem a vantagem de que você pode comentar as linhas que você não quer para desativá-los temporariamente
Josias Yoder
31

Use barras invertidas.

if [ $(do_something "arg1") ] || \
   [ $(do_something "arg2") ] || \
   [ $(do_something "arg3") ]
then
  echo "OK"
else
  echo "NOT OK"
fi

EDITAR

Além disso - quero garantir que, mesmo que a primeira condição seja verdadeira, todas as outras condições ainda serão avaliadas.

Isso não é possível em apenas uma declaração if. Em vez disso, você pode usar um loop for que itera sobre os argumentos e os avalia separadamente. Algo como:

do_something() {
  for x in "$@"
  do
    if [need to do something on $x]
    then
      do it
    else
      echo "no action required on $x"
    fi
  done
}
tectux
fonte
graças, tentou fazê-lo - eu recebo um erro[: do_something: unary operator expected
Itay
Você colocou cada avaliação entre seus próprios colchetes? Então, ao [ expr1 ] || [ expr2 ]invés de [ expr1 || expr2 ].
Tectux
sim, eu fiz: (...
Itay 11/11/2013
Meu palpite é que isso do_something "arg1"é interpretado como dois argumentos, enquanto a expressão deve ser unária. Qualquer maneira de fazer pode do_something "arg1"ser avaliada como um argumento?
Itay
11
Você está certo. Isso funciona também: if [ $(do_something "arg1") ].
Tectux
5

A sintaxe correta é:

if  do_something "arg1" || \
    do_something "arg2" || \
    do_something "arg3"
then
  echo "OK"
else
  echo "NOT OK"
fi

\ é usado para informar ao shell que um comando continua na próxima linha.

EDIT : Eu acho que isso deve fazer o que você quer:

#!/bin/bash

do_something() {
  if [need to do something on $1]
  then
    do it
    echo "OK"
  else
    echo "NOT OK"
  fi
}

do_something "arg1"
do_something "arg2"
do_something "arg3"
Eric Carvalho
fonte
Obrigado, resultados com um erro:[: too many arguments
Itay 11/11
@Itay Resposta atualizada.
Eric Carvalho
Atualizando a pergunta - esta ainda não é a resposta final :(
Itay
-1

Eu prefiro:

if {
    do_something "arg1" ||
    do_something "arg2" ||
    do_something "arg3"
}; then
    echo "OK"
else
    echo "NOT OK"
fi
Toxiro
fonte
Seu script não funcionará de todo: após o 1º parâmetro de teste, ele geraria um \ncaractere, portanto sua ifinstrução geraria alguns erros e do_somethingnão seriam nomes de comandos, portanto mais erros
damadam 17/12
Para mim, funciona no zsh e no bash, se do_somethingé uma função , é claro. do_somethingdeve ser função ou comando, o que mais deveria ser? Além disso, não vejo onde ele geraria um \npersonagem, exceto depois de ecoar o resultado e isso é esperado ...
Toxiro