Pourquoi la commande ci-dessous ne se ferme-t-elle pas? Plutôt que de sortir, la boucle fonctionne indéfiniment.
Alors que j'ai découvert ce comportement en utilisant une configuration plus complexe, la forme la plus simple de la commande se réduit à ce qui suit.
Ne quitte pas:
while /usr/bin/true ; do echo "ok" | cat ; done | exit 1
Il n'y a pas de fautes de frappe ci-dessus. Chaque '|' est une pipe. La «sortie 1» représente un autre processus qui s'est exécuté et s'est terminé.
Je m'attends à ce que la "sortie 1" provoque un SIGPIPE sur la boucle while (écrivez sur un tuyau sans lecteur) et que la boucle éclate. Mais, la boucle continue de fonctionner.
Pourquoi la commande ne s'arrête-t-elle pas?
linux
command-line
bash
shell
bash-scripting
stephen.z
la source
la source
Réponses:
Elle est due à un choix de mise en œuvre.
L'exécution du même script sur Solaris avec
ksh93
produit un comportement différent:Ce qui déclenche le problème, c'est le pipeline interne, sans lui, la boucle se termine quel que soit le shell / OS:
cat
reçoit un signal SIGPIPE sous bash mais le shell itère de toute façon la boucle.La documentation de Bash indique:
La documentation de Ksh indique:
POSIX déclare:
la source
echo
ignore SIGPIPE. Vous pouvez également reproduire le problème en utilisantenv echo
au lieu deecho
(pour forcer l'utilisation duecho
binaire réel ). (Comparez également la sortie de{ echo hi; echo $? >&2; } | exit 1
et{ env echo hi; echo $? >&2; } | exit 1
.)Ce problème me dérange depuis des années. Merci à Jilliagre pour le coup de pouce dans la bonne direction.
En reformulant un peu la question, sur ma boîte Linux, cela se termine comme prévu:
Mais si j'ajoute un tuyau, il ne se ferme pas comme prévu:
Cela m'a frustré pendant des années. En considérant la réponse écrite par jilliagre, j'ai trouvé cette merveilleuse solution:
QED ...
Enfin, pas tout à fait. Voici quelque chose d'un peu plus compliqué:
Cela ne fonctionne pas correctement. J'ai ajouté le
|| exit
afin qu'il sache comment se terminer tôt, mais le tout premierecho
ne correspond pas augrep
afin que la boucle se ferme immédiatement. Dans ce cas, vous n'êtes vraiment pas intéressé par le statut de sortie degrep
. Ma solution consiste à en ajouter un autrecat
. Alors, voici un script artificiel appelé "dizaines":Cela se termine correctement lors de l'exécution en tant que
tens | head
. Dieu merci.la source