si condition sur plusieurs lignes dans le shell bash

19

J'ai une fonction shell bash qui prend un argument et effectue quelque chose dessus si nécessaire.

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

Je veux appeler cette méthode avec plusieurs arguments et vérifier si au moins l'un d'entre eux a réussi.

J'ai essayé quelque chose comme:

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

Quelle sera la syntaxe correcte pour cela?
MODIFIER
également - Je veux m'assurer que même si la première condition est vraie, toutes les autres conditions seront toujours évaluées.

Merci,

Itay
la source
J'ai mis à jour ma réponse.
tectux
Merci, pouvez-vous donner un exemple?
Itay
1
J'ai ajouté un exemple de code à ma réponse.
tectux

Réponses:

7

Exécutez d'abord les commandes, puis vérifiez si au moins l'une d'elles a réussi.

#!/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
la source
3
C'est déroutant, je serais heureux si vous pouviez fournir des explications sur le fonctionnement des instructions conditionnelles dans bash ..., do_something renvoie 0 en cas de succès, mais nous mettons à jour success à 1 ..., if ((success))évalue à quelque chose de différent de if success. Je suis confus :)
Itay
2
@Itay ((...))est une commande arithmétique. Si le résultat à l'intérieur est différent de zéro, il renvoie vrai (0). Si le résultat à l'intérieur est 0, il renvoie false (1). "succès" est traité comme une variable qui devrait contenir un nombre. Voir mywiki.wooledge.org/ArithmeticExpression
geirha
Merci, je suppose que la partie qui m'a dérouté est que 0 est vrai et 1 est faux généralement c'est le contraire :)
Itay
2
@Itay Oui, cela peut être déroutant au début. Bash diffère des langages à usage général en ce qu'il est "basé sur les commandes"; il n'appelle pas de fonctions, il n'a pas de classes et de méthodes, il exécute des commandes et teste les états de sortie des commandes. Et il est beaucoup plus facile d'exécuter des commandes en bash que des langages comme C, python, java, perl, etc. Les commandes sortent avec 0 pour signaler le succès, et 1-255 pour divers types d'échecs. (Une commande ne peut généralement réussir que dans un sens, mais échouer pour différentes raisons)
geirha
2
Cette solution a l'avantage que vous pouvez commenter les lignes dont vous ne voulez pas les désactiver temporairement
Josiah Yoder
31

Utilisez des barres obliques inverses.

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

ÉDITER

Aussi - je veux m'assurer que même si la première condition est vraie, toutes les autres conditions seront toujours évaluées.

Ce n'est pas possible dans une seule instruction if. Au lieu de cela, vous pouvez utiliser une boucle for qui itère sur les arguments et les évalue séparément. Quelque chose comme:

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
la source
merci, j'ai essayé - je reçois une erreur[: do_something: unary operator expected
Itay
Avez-vous placé chaque évaluation entre ses propres crochets? Donc [ expr1 ] || [ expr2 ]au lieu de [ expr1 || expr2 ].
tectux
oui, je l'ai fait: (...
Itay
Je suppose que cela do_something "arg1"est interprété comme deux arguments alors que l'expression devrait être unaire. Une manière de faire do_something "arg1"être évaluée comme un argument?
Itay
1
Tu as raison. Cela fonctionne aussi: if [ $(do_something "arg1") ].
tectux
5

La syntaxe correcte est:

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

\ est utilisé pour indiquer au shell qu'une commande continue sur la ligne suivante.

EDIT : Je pense que cela devrait faire ce que vous voulez:

#!/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
la source
Merci, résultats avec une erreur:[: too many arguments
Itay
@Itay Answer updated.
Eric Carvalho
Mise à jour de la question - ce n'est pas encore la réponse finale :(
Itay
-1

Je préfère:

if {
    do_something "arg1" ||
    do_something "arg2" ||
    do_something "arg3"
}; then
    echo "OK"
else
    echo "NOT OK"
fi
Toxiro
la source
Votre script ne fonctionnera pas du tout: après le 1er paramètre de test, il générerait un \ncaractère, donc votre ifdéclaration générerait des erreurs et do_somethingne sont pas des noms de commande, donc plus d'erreurs
damadam
Pour moi, cela fonctionne en zsh et bash, IF do_somethingest une fonction bien sûr. do_somethingdoit être fonction ou commande, quoi d'autre devrait-il être? De plus je ne vois pas où cela générerait un \npersonnage sauf après avoir fait écho au résultat et cela est attendu ...
Toxiro