Je voudrais faire un pipeline de scripts Bash comme ça
prog1 | prog2
tel que prog2 peut voir le code de sortie de prog1 et agir différemment en fonction de cette information.
Est-ce possible?
La réponse générale est non. Il est possible que prog2
se prog2
avant que prog1
ne démarre (évidemment cela ne peut pas se produire si prog2
lit une input, ce que vous attendez d'elle si vous l'utilisez dans un pipeline). Il est certainement possible pour prog2
de quitter avant prog1
; cela arrive par exemple lorsque prog2
est un programme de search qui se ferme dès qu'il trouve une correspondance, auquel cas prog1
n'a peut-être pas encore fini de produire toutes datatables.
Il n'y a pas de moyen direct pour prog2
de récupérer le statut de sortie de prog1
ou même de savoir que prog1
est sorti. Tout ce que prog2
peut savoir, c'est que prog1
a fermé son extrémité de tuyau, ce qu'il peut faire sans mourir.
Si vous souhaitez get le statut de sortie de prog1
partir de prog2
, il existe deux methods courantes: vous pouvez l'écrire dans un file ou l'envoyer via le canal. L'envoi de l'état de sortie en tant que dernière ligne des données apathées est une possibilité. Vous devez vous assurer de ne pas traiter la dernière ligne jusqu'à ce que vous sachiez que c'est la dernière ligne, c'est-à-dire jusqu'à ce que vous ayez essayé de lire la ligne suivante.
{ prog1; echo $?; } | …
Voici un exemple où le côté droit est un filter de text qui colore chaque ligne contenant le mot "erreur" en rouge. Si le côté gauche échoue, le côté droit se termine avec le même statut.
{ prog1; echo $?; } | awk ' NR != 1 { if (line ~ /[Ee][Rr][Rr][Oo][Rr]/) print "\033[31m" line "\033[0m"; else print line; } {line = $0} END {exit($0)} '
Bien que vous puissiez dans certains cas spéciaux (voir les autres réponses) vous ne pouvez pas dans tous les cas. Certains programmes de filtrage continueront tout simplement, tandis que d'autres conserveront toutes les sorties, les libéreront en une seule fois, puis sortiront.
Pour un exemple de programme "juste continuer", grep
va server, tout comme tail -f /var/log/some_log_file
. L'utilisation d'un sort
dans un pipeline provoque un «décrochage», car le sort
va collecter des données jusqu'à ce que le tube qui se trouve devant se ferme. L'utilisation de xargs
ajoute une complication supplémentaire: les programmes lancés par xargs
(il peut démarrer plusieurs instances) font-ils partie du pipeline ou non?
La réponse: Pas directement.
@terdon a illustré que le code de sortie de la command précédente dans le tube doit être envoyé comme paramètre explicite à la command suivante.
Rappelez-vous que le canal est simplement un mappage du STDOUT de la command précédente au STDIN de la command suivante; les codes de sortie ne sont pas fournis à STDOUT (ou STDERR).
Tous les process, dans le pipeline, sont démarrés avant toute sortie. Par conséquent prog2
pourrait avoir à get cette information après qu'il a commencé, il devrait également tenir le traitement jusqu'à ce que prog1
soit sorti, cela pourrait bloquer le tuyau. Il semble y avoir des problèmes fondamentaux à faire ce que vous requestz, pas les limitations du operating system.
Vous devez probablement considérer un file temporaire ou mettre le résultat dans une variable.
Exemple pour une petite quantité de données, en utilisant une variable.
tmp=$(prog1) if test "z$PIPESTATUS" == "z0" then … else … fi
Pour finir la réponse de Gilles ,
(prog1; echo $? > /tmp/prog1.status) | prog2
est une approche. prog2
pourrait soit
/tmp/prog1.status
, ou /tmp/prog1.status
périodiquement en lisant l'input standard.