J'écris un script dans Bash pour tester du code. Cependant, il semble idiot d'exécuter les tests si la compilation du code échoue en premier lieu, auquel cas je vais simplement abandonner les tests.
Existe-t-il un moyen de le faire sans encapsuler l'intégralité du script dans une boucle while et utiliser des pauses? Quelque chose comme un dun dun dun goto?
1
cohérente. Si le script est destiné à être exécuté par un autre script, vous souhaiterez peut-être définir votre propre ensemble de codes d'état avec une signification particulière. Par exemple,1
== les tests ont échoué,2
== la compilation a échoué. Si le script fait partie d'autre chose, vous devrez peut-être ajuster les codes pour qu'ils correspondent aux pratiques utilisées. Par exemple, lorsqu'une partie de la suite de tests est exécutée par automake, le code77
est utilisé pour marquer un test ignoré.exit #
commande dans une fonction, pas dans un script. (Dans ce cas, utilisezreturn #
plutôt.)exit 0
quittez donc le script et renvoie 0 (indiquant aux autres scripts qui pourraient utiliser le résultat de ce script qu'il a réussi)Utilisez set -e
Le script se terminera après la première ligne qui échoue (retourne un code de sortie différent de zéro). Dans ce cas, la commande qui échoue2 ne s'exécutera pas.
Si vous deviez vérifier l'état de retour de chaque commande, votre script ressemblerait à ceci:
Avec set -e, cela ressemblerait à:
Toute commande qui échoue entraînera l'échec de tout le script et renverra un état de sortie que vous pouvez vérifier avec $? . Si votre script est très long ou que vous construisez beaucoup de choses, cela deviendra assez moche si vous ajoutez des contrôles d'état de retour partout.
la source
set -e
vous encore peut faire une sortie de commandes avec des erreurs sans arrêter le script:command 2>&1 || echo $?
.set -e
abandonnera le script si un pipeline ou une structure de commande renvoie une valeur non nulle. Par exemplefoo || bar
, échouera uniquement si les deuxfoo
etbar
renvoient une valeur non nulle. Habituellement, un script bash bien écrit fonctionnera si vous ajoutezset -e
au début et l'addition fonctionne comme un test de validité automatisé: abandonnez le script si quelque chose se passe mal.set -o pipefail
option.set -e
serait justemake || exit $?
.set -u
. Jetez un oeil à l' officieux mode strict bash :set -euo pipefail
.Un gars de SysOps m'a une fois appris la technique de la griffe à trois doigts:
Ces fonctions sont * NIX OS et shell-robustes. Mettez-les au début de votre script (bash ou autre),
try()
votre déclaration et votre code.Explication
(basé sur le commentaire d'un mouton volant ).
yell
: affiche le nom du script et tous les arguments dansstderr
:$0
est le chemin d'accès au script;$*
sont tous des arguments.>&2
signifie>
rediriger stdout vers & pipe2
. la pipe1
seraitstdout
elle-même.die
fait la même chose queyell
, mais quitte avec un état de sortie différent de 0 , ce qui signifie «échouer».try
utilise le||
(booléenOR
), qui n'évalue le côté droit que si celui de gauche a échoué.$@
est à nouveau tous les arguments, mais différents .la source
$0
est le chemin d'accès au script.$*
sont tous des arguments.>&2
signifie ">
rediriger la sortie standard vers le&
tuyau2
". le tuyau 1 serait lui-même standard. donc yell préfixe tous les arguments avec le nom du script et les imprime sur stderr. die fait la même chose que crier , mais sort avec un statut de sortie différent de 0, ce qui signifie «échouer». try utilise le booléen ou||
, qui n'évalue le côté droit que si celui de gauche n'a pas échoué.$@
est à nouveau tous les arguments, mais différents . espérons que cela explique toutdie() { yell "$1"; exit $2; }
que vous puissiez passer un message et quitter le code avecdie "divide by zero" 115
.yell
etdie
. Maistry
pas tant que ça. Pouvez-vous fournir un exemple de votre utilisation?Si vous appelez le script avec
source
, vous pouvez utiliserreturn <x>
où<x>
sera l'état de sortie du script (utilisez une valeur non nulle pour erreur ou faux). Mais si vous invoquez un script exécutable (c'est-à-dire directement avec son nom de fichier), l'instruction return entraînera une réclamation (message d'erreur "return: ne peut" retourner "qu'à partir d'une fonction ou d'un script source").Si
exit <x>
est utilisé à la place, lorsque le script est invoqué avecsource
, il entraînera la fermeture du shell qui a démarré le script, mais un script exécutable se terminera comme prévu.Pour gérer l'un ou l'autre cas dans le même script, vous pouvez utiliser
Cela gérera toute invocation appropriée. Cela suppose que vous utiliserez cette instruction au niveau supérieur du script. Je déconseille de quitter directement le script depuis une fonction.
Remarque:
<x>
est censé être juste un nombre.la source
J'inclus souvent une fonction appelée run () pour gérer les erreurs. Chaque appel que je veux faire est passé à cette fonction, donc le script entier se ferme lorsqu'un échec est rencontré. L'avantage de ceci par rapport à la solution set -e est que le script ne se ferme pas silencieusement lorsqu'une ligne échoue et peut vous dire quel est le problème. Dans l'exemple suivant, la 3ème ligne n'est pas exécutée car le script se ferme lors de l'appel à false.
la source
set -e option
. Ensuite , la commande, car il est avec des arguments, j'ai utilisé des guillemets simples pour éviter les problèmes de bash comme ceci:runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'
. Remarque J'ai changé le nom de la fonction en runTry.eval
est potentiellement dangereux si vous acceptez des entrées arbitraires, mais sinon cela a l'air plutôt bien.Au lieu de
if
construire, vous pouvez tirer parti de l' évaluation de court-circuit :Notez la paire de parenthèses qui est nécessaire en raison de la priorité de l'opérateur d'alternance.
$?
est une variable spéciale définie pour quitter le code de la dernière commande appelée.la source
command -that --fails || exit $?
ça fonctionne sans parenthèses, qu'est-ceecho $[4/0]
qui nous amène à en avoir besoin?echo $[4/0] || exit $?
) bash n'exécutera jamais leecho
, sans parler d'obéir au||
.J'ai la même question mais je ne peux pas la poser car ce serait un doublon.
La réponse acceptée, en utilisant exit, ne fonctionne pas lorsque le script est un peu plus compliqué. Si vous utilisez un processus d'arrière-plan pour vérifier la condition, exit ne quitte que ce processus, car il s'exécute dans un sous-shell. Pour tuer le script, vous devez le tuer explicitement (du moins c'est la seule façon que je connaisse).
Voici un petit script sur la façon de le faire:
C'est une meilleure réponse mais toujours incomplète. Je ne sais vraiment pas comment me débarrasser de la partie de la flèche .
la source