yes "test" | grep -m3 "test"
odbitki
test
test
test
a następnie kończy się. Tak też jest
yes "test" | while read line; do echo $line; done | grep -m3 "test"
i
yes "test" | while read line; do echo $line; done | grep -E "*" | grep -m3 "test"
Ale
yes "test" | while read line; do echo $line | grep -E "*"; done | grep -m3 "test"
odbitki
test
test
test
a następnie zawiesza się. Co tu się dzieje?
grep
rzecz, ponieważ widać to samo zawieszenieyes "test" | while read line; do echo $line | cat; done | head -3
. Usuń| cat
i nie zawiesza się.set -x
, zobaczysz, że pętla działa znacznie więcej niż 3 razy we wszystkich przypadkach (prawdopodobnie wystarczająca do opróżnienia bufora w przypadkach, w których umiera).Odpowiedzi:
W
uruchomione są cztery procesy,yes
program powłoki działający w tejwhile
pętligrep
igrep
odpowiednio. Ostatni proces w potoku kończy się, zamykając czytany koniec potoku wejściowego po trzech dopasowaniach. Rurociąg kończy się następnie łańcuchemSIGPIPE
s w zwykły sposób dla rurociągów przedwcześnie zakończonych, ponieważ każdy etap rurociągu z kolei kończy się zapisem na zepsutej rurze.W
działają trzy procesyyes
, odpowiednio program powłokigrep
. Ale drugi proces, ten, w którym uruchomiony jest program powłoki, nieustannie odradza dwa kolejne procesy potomne, jeden wykonujący,echo
a drugi uruchamiający innągrep
instancję. To ten ostatni proces jest wysyłany,SIGPIPE
a nie proces uruchamiający program powłoki. Jest to ten ostatni proces, który w rzeczywistości polega na pisaniu na zepsutej rurze.Konsekwencją tego jest to, że drugi etap potoku, powłoka działająca w tej
while
pętli, nigdy sam się nie kończySIGPIPE
i po prostu działa dalej, odradzając potok potomny; raz po raz. Widzi, że potok potomny, który się pojawił, kończy sięSIGPIPE
oczywiście, ale dla powłoki działającej wwhile
pętli, która nie jest powodem do zakończenia pętli.źródło