Le set -e
est le problème ici: -e
signifie « sortie si quelque chose échoue », où « échoue » est défini comme « sort différent de zéro ».
Nous voyons dans la sortie, les dernières lignes:
+ check_run .gitmodules 'git submodule update --init --recursive'
+ echo ''
+ grep --quiet .gitmodules
(et rien d'autre). Le script est sorti après grep --quiet
.
est ici la définition réelle de check_run
:
check_run() {
echo "$changed_files" | grep --quiet "$1" && eval "$2"
}
Ce parse comme left && right
où gauche est le echo ... | grep ...
et droit est le eval "$2"
.
Nous voyons que la partie gauche a couru et la partie droite n'a pas fonctionné. Voici où nous devons savoir quelque chose sur les shells: même avec -e
ensemble, ils ne immédiatement quitter quitter si quelque chose échoue, tant que ce quelque chose fait partie d'un test. Donc, ce n'est pas immédiatement le problème.
Mais c'est toujours le problème, car left && right
a comme statut de sortie l'état de sortie de la dernière chose qu'il exécute. La dernière chose qu'il a couru est le pipeline gauche, qui était echo ... | grep ...
. Le statut de sortie du pipeline est le statut de sortie de son dernier composant, , c'est-à-dire grep
. Le grep sort zéro si elle trouve la chaîne (et avec --quiet
, supprime sa sortie aussi bien), 1 sinon, et 2 sur les erreurs génériques, de sorte que l'état de sortie est 1.
Par conséquent, l'état de sortie de left && right
était aussi 1.
Par conséquent, puisque -e
était en vigueur, le shell est sorti! La solution est d'éviter -e
(mais cela signifie que si quelque chose d'autre échoue de façon inattendue, l'interpréteur de commandes s'enfonce, donc cela peut être un peu dangereux), ou de s'assurer que le left && right
ne fait pas sortir le shell.
Il y a une façon simple de faire de celui-ci: remplacer left && right
avec if left; then right; fi
:
if echo "$changed_files" | grep --quiet "$1"; then
eval "$2"
fi
Notez que si eval "$2"
échoue, le shell sortie encore.
Il existe une manière différente et légèrement compliquée de faire cela avec un effet différent: remplacer left && right
par left && right || true
. Le "et" l'expression est plus prioritaire, de sorte que cela signifie:
- Évaluer gauche
- Si cela réussit (sort zéro), évaluer droit
- Si l'
&&
échoue (soit gauche sorties non nulles, ou à droite est exécuté et à droite quitte non zéro), évaluez la partie || true
, qui quitte 0.
Par conséquent:
echo "$changed_files" | grep --quiet "$1" && eval "$2" || true
sort toujours 0, eval
-ment "$2"
si et seulement si le côté gauche échoue (ne trouve pas la pour l'expression rassemblés de).
Si vous voulez que check_run
s'accroche même si eval "$2"
échoue, utilisez la seconde version (|| true
). Si vous souhaitez que check_run
s'arrête (et que la sortie du shell complète) sous -e
échoue, utilisez la première version (if ...; then
).
très ancienne 4BSD /bin/sh
, bien avant qu'il ne se open source, avait un bug: -e
aurait faire la sortie de la coquille dans ces cas. (Je pense que je fixe moi-même à un moment donné, mais quand 4BSD est allé à un nouveau sh, et non à partir du code original de Steve Bourne, le bug n'était pas là du tout.)
En bash, vous pouvez contrôler cela plus en détail. En particulier, vous pouvez obtenir le statut chaque composant d'un pipeline dans la variable de tableau $PIPESTATUS
.
peut-être spécifier le chemin d'accès complet au binaire 'npm'? – t0mm13b
@ t0mm13b Si vous regardez l'image, vous pouvez voir qu'elle n'arrive même pas à la ligne avec npm mais échoue plutôt pendant/après grep. C'est pourquoi j'ai inclus les lignes d'écho – jth41
même avec grep, inclure un chemin complet à n'importe quel binaire, pourquoi ne pas renvoyer le code d'erreur '$?' De la dernière commande exécutée. – t0mm13b