Подумайте об этом, на мгновение.
- Вы сообщаете оболочке, что весь ваш конвейер должен считаться неудачным, если какой-либо компонент вышел из строя.
- Вы говорите
zcat
, чтобы записать свой вывод в head
.
- Затем вы сообщаете
head
для выхода после чтения 12 строк из потока входного потока с гораздо большей длиной, чем 12 строк.
Из конечно у вас есть ошибка: zcat
имеет свой трубопровод назначения закрыты рано, и был не в состоянии успешно написать распакованную версию входного файла! У него нет никакого способа узнать, что это было связано с намерением пользователя, через что-то ошибочное.
Если вы использовали zcat
для записи на диск, и на нем не хватило места или в сетевом потоке, и была потеря связи, было бы совершенно правильно и целесообразно выйти со статусом, указывающим на сбой , Это просто еще один случай этого правила.
Специфическая ошибка, которая zcat
уделяется операционной системой EPIPE
, возвращаемая write
системного вызова при следующих условиях: Сделана попытка записать в канал, который не открыт для чтения с помощью любого обработать.
После head
(единственный читатель этого FIFO) завершился, для любой записи на входной стороне трубопровода не вернуть EPIPE будет ошибка. Для zcat
, чтобы молча игнорировать ошибку, записывая свой вывод, и, таким образом, иметь возможность генерировать неточный выходной поток без статуса выхода, отражающего это событие, будет аналогичным образом быть ошибкой.
Если вы не хотите, чтобы изменить какие-либо из ваших вариантов оболочки, кстати, один обходной путь можно рассмотреть с помощью процесса замещения:
var=$(head -n 12 < <(zcat file.gz))
В этом случае zcat
не компонент трубопровода и его статус выхода не рассматриваются для целей определения успеха. (Вы можете проверить, является ли $var
длиной 12 строк, если вы хотите найти независимое определение успеха/отказа).
В качестве отложенного 'set -e' и' set -u' являются ... как бы любезно ... * противоречивыми *, с множеством тонких угловых случаев (и непоследовательностью поведения в каждой версии, где попытки были сделаны для изменения деталей, не указанных в POSIX, в их поведении между релизами).Если вы не понимаете все сценарии, описанные в [BashFAQ # 105] (http://mywiki.wooledge.org/BashFAQ/105) и [BashFAQ # 112] (http://mywiki.wooledge.org/BashFAQ/112), и вам не нужна совместимость с релизами bash, с которыми вы не можете протестировать, вы можете пересмотреть их использование. Статическая проверка с помощью http://shellcheck.net/ имеет меньшее количество оговорок. –
(Напротив, 'pipefail' - это, как правило, хорошая идея, когда у вас есть конкретный случай, когда вы хотите разрешить компонент конвейера сбой, вы можете разрешить это явно, для этого случая: var = $ ({zcat file. gz || :;} | head -n 12) 'будет делать). –
... в сторону: нижний регистр 'var' правильный; см. [спецификацию переменной среды POSIX] (http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html): имена всех крышек используются переменными со значением для оболочки или системы; Имена нижнего регистра зарезервированы для использования приложения. Это относится и к неэкспортированным переменным оболочки, так как установка переменной оболочки будет перезаписывать любую переменную среды с похожим именем. –