web-dev-qa-db-fra.com

Comment quitter un script Shell en cas d'échec d'une partie?

Comment puis-je écrire un script Shell qui se termine, si une partie de celui-ci échoue? Par exemple, si l'extrait de code suivant échoue, le script doit se fermer.

n=0
until [ $n -ge 5 ]
do
  gksu *command* && break
  n=$[$n+1]
  sleep 3
58
Weylyn

Une approche consisterait à ajouter set -e au début de votre script. Cela signifie (de help set):

  -e  Exit immediately if a command exits with a non-zero status.

Donc, si l'une de vos commandes échoue, le script se termine.

Vous pouvez également ajouter des instructions exit explicites aux points de défaillance possibles:

command || exit 1
98
terdon

Vous pouvez quitter un script à n'importe quel endroit à l'aide du mot clé exit. Vous pouvez également spécifier un code de sortie afin d'indiquer à d'autres programmes que ou comment votre script a échoué, par exemple exit 1 ou exit 2 etc. (par convention, le code de sortie 0 est pour le succès et tout ce qui est supérieur à 0 signifie l'échec; cependant, par convention également, les codes de sortie supérieurs à 127 sont réservés pour une terminaison anormale (par exemple par un signal)).

La construction générique pour sortir en cas d'échec est

if [ failure condition ]; then
    exit n
fi

avec failure condition et n appropriés. Mais dans des scénarios spécifiques, vous pouvez procéder différemment. Maintenant, pour votre cas, j'interprète votre question selon laquelle si l'une des cinq invocations de gksu échoue, alors vous voulez quitter. Une façon consiste à utiliser une fonction comme celle-ci

function try_command {
    for i in 1 2 3 4 5 ; do
        if gksu command ; then
            return 0
        fi
    fi
    exit 1
}

puis appelez la boucle par try_command.

Il existe des moyens (plus) avancés ou sophistiqués de répondre à votre question. Cependant, la solution ci-dessus est plus accessible aux débutants que, disons, la solution de Stéphane.

17
countermode
attempt=0
until gksu command; do
  attempt=$((attempt + 1))
  if [ "$attempt" -gt 5 ]; then
    exit 1
  fi
done

exit quitte le script sauf s'il est appelé dans un sous-shell. Si cette partie du script est dans un sous-shell, par exemple parce qu'elle se trouve dans (...) Ou $(...) ou une partie d'un pipeline, alors elle ne quittera que ce sous-shell.

Dans ce cas, si vous souhaitez que le script se termine en plus du sous-shell, vous devrez alors appeler exit à la sortie de ce sous-shell.

Par exemple, ici avec 2 niveaux imbriqués de sous-coquilles:

(
  life=hard
  output=$(
    echo blah
    [ "$life" = easy ] || exit 1 # exit subshell
    echo blih not run
  ) || exit # if the subshell exits with a non-zero exit status,
            # exit as well with the same exit status

  echo not run either
) || exit # if the subshell exits with a non-zero exit status,
          # exit as well with the same exit status

Cela peut devenir plus compliqué si le sous-shell fait partie d'un pipeline. bash a un tableau spécial $PIPESTATUS, similaire à celui de zsh$pipestatus qui peut vous aider ici:

{
   echo foo
   exit 1
   echo bar
} | wc -c
subshell_ret=${PIPESTATUS[0]}
if [ "$subshell_ret" -ne 0 ]; then
  exit "$subshell_ret"
fi
11
Stéphane Chazelas

Le piège effectuera une action lors de la réception d'un signal.

trap "echo EXIT;  exit" 0
trap "echo HUP;   exit" 1
trap "echo CTL-C; exit" 2
trap "echo QUIT;  exit" 3
trap "echo ERR;   exit" ERR
n=0
until [ $n -ge 5 ]
do
  n=$[$n+1]
  echo $n
  sleep 3
done

Exécutez-le et laissez-le sortir normalement. Il intercepte le signal 0.

EXIT

Exécutez-le à nouveau et interrompez avec ^ C. Il intercepte à la fois le signal 2 et le signal 0.

CTL-C
EXIT

Un état de sortie différent de zéro se bloquera sur ERR

ERR
EXIT
3
RobP