Un programme situé dans un pipeline peut-il voir le code de sortie du programme précédent?

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

  • lire l'input standard à la fin, puis lire /tmp/prog1.status , ou
  • vérifier l'existence de /tmp/prog1.status périodiquement en lisant l'input standard.