Команда Pipe для хвоста: когда первая команда прервана?

В этом примере:

$ for i in {1..3}; do sleep 1; echo $i; done | head -n 2 

почему первая команда (для цикла) убита только перед отображением 3 ? Я ожидал, что он будет убит сразу после отображения 2 .

Проблема, которую я пыталась решить изначально, была такой:

 $ for i in *(/); do c=`find "$i" -iname "*.ext" | wc -l`; echo "$c $i"; done | head -n 3 

Я ожидал, что это закончится, как только на экране появятся три строки, но он четыре раза запускает цикл, отбрасывая четвертую строку.

То, что я думал, произойдет:

 sleep 1 echo 1 sleep 1 echo 2 # 2 is printed and the for loop is killed 

Что на самом деле происходит:

 sleep 1 echo 1 sleep 1 echo 2 sleep 1 echo 3 # 3 is not printed and the for loop is killed 

Есть ли способ прервать цикл сразу после заданного количества итераций без добавления какой-либо логики внутри самого цикла?

SIGPIPE отправляется только тогда, когда программа пытается записать в закрытый канал. Было бы неплохо отправить SIGPIPE в противном случае: программы, которые имеют открытый канал, могут даже не знать об этом и не должны быть убиты, если они никогда не взаимодействуют с трубой.

In for i in 1 2 3; do sleep 1; echo $i; done for i in 1 2 3; do sleep 1; echo $i; done for i in 1 2 3; do sleep 1; echo $i; done , команда sleep ничего не пишет, поэтому он не получит сигнал. Только когда echo запускается, SIGPIPE отправляется.

В общем, SIGPIPE не предназначен для точной работы. Это предназначено только для того, чтобы программы, чья работа заключалась в том, чтобы производить какой-то результат, не работают постоянно, когда потребитель этой продукции уходит. В большинстве практических сценариев программа на левой стороне буферов труб записывает, и он будет получать SIGPIPE только в следующий раз, когда он сбросит свой буфер.

Если вы хотите остановить цикл после нескольких итераций, постройте эту логику в цикле.

На моих разных оболочках (ksh, zsh, bash) у меня есть ожидаемый bahaviour: у меня только 1, 2, а не 3. Проблема здесь может быть связана с тем, как SIGPIPE обрабатывается в вашей версии ZSH.

Можете ли вы попробовать запустить эти команды с помощью экземпляра «env-free»? например, без псевдонимов, конфигурации и т. д. …

Как указано в комментариях, оболочка получает ошибку, когда он хочет что-то повторить (с помощью функции write ()). Пока целая цепь цепей работает (процесс head все еще работает и открыт его STDIN), все идет хорошо. Но когда head оканчивается, выход вашей оболочки никуда не будет (сломанная труба).

Но пока оболочка не попытается что-то написать в своем выступлении, он не знает, что труба сломана и продолжает его обработку.

Таким образом, вы увидите «эхо-сигнал 3» при отладке, который завершится с ошибкой и завершает работу оболочки.