SIGPIPE и bash pipefail

SIGPIPE и bash pipefail

Я пытаюсь лучше понять SIGPIPE в Linux.

Я провел этот эксперимент: { ls -al /tmp/ ; echo "$?" 1>&2 ; } | head и он выводит эхо 141, которое, как я понимаю, является кодом выхода, который присваивается процессам, которые завершаются с помощью SIGPIPE Раньше я делал это много раз, не понимая нюансов, SIGPIPEи я обычно запускаю с помощью set -eEuo pipefail, поэтому я пытался понять, почему мой код не давал сбой все время из-за сломанных каналов... Поэтому я провел этот другой эксперимент: ( set -o pipefail; { ls -al /tmp/ ; echo "$?" 1>&2 ; } | head; )и в тот раз я получил 0 в эхо... так что когда pipefailвключено, это означает, что SIGPIPEоно подавлено? или я неправильно понимаю, что здесь происходит?

решение1

lsможет успеть записать весь свой вывод до headвыхода и разрыва конвейера, даже если вывод lsдлиннее, чем то, что headпечатается. Это происходит потому, что:

  • headможет прочитать больше, чем в конечном итоге напечатать,
  • и в любом случае для трубы есть буфер.

SIGPIPE запускается фактической записью в сломанный канал. Если lsуспеет записать весь свой вывод до headвыхода, то не будет никакого акта записи, который запускает SIGPIPE.

Или lsможет не успеть записать весь свой вывод перед headвыходом. Тогда он попытается записать больше и получит SIGPIPE.

Поскольку lsи headработают параллельно, я думаю, что в общем случае есть состояние гонки. Может случиться так, что какой-то конкретный вывод из lsвызывает или не вызывает SIGPIPE, случайным образом.

Попробуйте yesвместо ls …:

{ yes ; echo "$?" 1>&2 ; } | head

или

( set -o pipefail; { yes ; echo "$?" 1>&2 ; } | head; )

yesгенерирует вывод, который не заканчивается сам по себе, поэтому после headвыхода всегда будет акт записи, который запускает SIGPIPE. Каждая из приведенных выше команд даст вам 141наверняка.

Это не имеет никакого отношения к pipefail.

Связанный контент