J'essaie de comprendre comment l'état de sortie est communiqué lorsqu'un tuyau est utilisé. Supposons que j'utilise which
pour localiser un programme inexistant:
which lss
echo $?
1
Depuis l' which
échec de la localisation, lss
j'ai obtenu un statut de sortie de 1. C'est très bien. Cependant, lorsque j'essaie ce qui suit:
which lss | echo $?
0
Cela indique que la dernière commande exécutée s'est terminée normalement. La seule façon dont je peux comprendre cela est que peut-être PIPE produit également un statut de sortie. Est-ce la bonne façon de le comprendre?
bash
shell-script
pipe
exit
sshekhar1980
la source
la source
which lss | echo $?
, leecho
est démarré avantwhich
sa sortie; le shell générant la ligne de commande pourecho
n'a aucun moyen de savoir quel sera le statut de sortie dewhich
plus tard.Réponses:
L'état de sortie du pipeline est l'état de sortie de la dernière commande du pipeline (sauf si l'option shell
pipefail
est définie dans les shells qui le prennent en charge, auquel cas l'état de sortie sera celui de la dernière commande du pipeline qui se termine avec un statut non nul).Il n'est pas possible de sortir l'état de sortie d'un pipeline à partir d' un pipeline, car il n'y a aucun moyen de savoir quelle serait cette valeur jusqu'à ce que le pipeline ait réellement terminé son exécution.
Le pipeline
est absurde car
echo
ne lit pas son entrée standard (les pipelines sont utilisés pour passer des données entre la sortie d'une commande à l'entrée de la suivante). Leecho
n'imprimerait pas non plus l'état de sortie du pipeline, mais l'état de sortie de la commande s'exécutait immédiatement avant le pipeline.Ceci est un meilleur exemple:
Cela signifie qu'un pipeline peut également être utilisé avec
if
:la source
L'état de sortie d'un tuyau est l'état de sortie de la commande de droite. Le statut de sortie de la commande de gauche est ignoré.
(Notez que
which lss | echo $?
cela ne s'affiche pas. Vous devez exécuterwhich lss | true; echo $?
pour afficher cela. Danswhich lss | echo $?
,echo $?
indique l'état de la dernière commande avant ce pipeline.)La raison pour laquelle les shells se comportent de cette façon est qu'il existe un scénario assez courant où une erreur dans la partie gauche doit être ignorée. Si le côté droit sort (ou ferme plus généralement son entrée standard) pendant que le côté gauche écrit toujours, alors le côté gauche reçoit un signal SIGPIPE. Dans ce cas, il n'y a généralement rien de mal: le côté droit ne se soucie pas des données; si le rôle du côté gauche est uniquement de produire ces données, il est normal que cela s'arrête.
Cependant, si le côté gauche meurt pour une raison autre que SIGPIPE, ou si le travail du côté gauche n'était pas uniquement de produire des données sur la sortie standard, une erreur dans le côté gauche est une véritable erreur qui doivent être signalés.
En clair, la seule solution est d'utiliser un tube nommé.
Dans ksh, bash et zsh, vous pouvez demander au shell d'effectuer une sortie de pipeline avec un statut différent de zéro si un composant du pipeline se termine avec un statut différent de zéro. Vous devez définir l'
pipefail
option:set -o pipefail
shopt -s pipefail
setopt pipefail
(ousetopt pipe_fail
)Dans mksh, bash et zsh, vous pouvez obtenir l'état de chaque composant du pipeline à l'aide de la variable
PIPESTATUS
(bash, mksh) oupipestatus
(zsh), qui est un tableau contenant l'état de toutes les commandes du dernier pipeline (une généralisation de$?
).la source
Oui, PIPE produit un état de sortie; si vous voulez le code de sortie de la commande avant le PIPE, vous pouvez utiliser
$PIPESTATUS
Selon ce Q&A de débordement de pile , pour imprimer l'état de sortie d'une commande lorsque vous utilisez un tuyau, vous pouvez faire:
Ou définissez pipefail avec la commande
set -o pipefail
(pour le désactiver, faitesset +o pipefail
), et utilisez$?
plutôt que$PIPESTATUS
.Ces commandes ne fonctionnent qu'après les avoir exécutées au moins une fois; cela signifie
PIPESTATUS
que cela ne fonctionne que lorsque vous l'exécutez après la commande avec le canal, comme ceci:Vous obtiendrez 10 pour
${PIPESTATUS[0]}
et 1 pour${PIPESTATUS[1]}
. Voir ce Q&R U&L pour plus d'informations.la source
PIPESTATUS
contienne les états de sortie des commandes du dernier pipeline, votre premier exemple n'a pas plus de sens que celuisomecmd | echo $?
que Kusalananda a traité dans sa réponse.false; true | echo $PIPESTATUS
imprime1
pour l'état de sortie defalse
.|exho
est vraiment déroutantLe shell évalue la ligne de commande avant l'exécution du pipeline. La
$?
valeur de la dernière commande exécutée avant le pipeline l'est également. Qu'il soitecho
lui-même démarré avant ou aprèswhich
est sans importance.Maintenant, si votre question concernait spécifiquement la propagation du statut de sortie, vous pouvez étudier le comportement par défaut comme ceci:
Comme vous pouvez le voir, l'état de sortie d'un pipeline est l'état de sortie de sa dernière commande.
la source