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,


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

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
}

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"

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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.