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
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
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.
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
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