2017-01-06 1 views
4
set -eu 
VAR=$(zcat file.gz | head -n 12) 

работает отличноbash zcat head вызывает неудачу?

set -eu -o pipefail 
VAR=$(zcat file.gz | head -n 12) 

, вызывает Баш, чтобы выйти с отказом. Как это вызвало неудачу?

Обратите внимание, что файл.gz содержит миллионы строк (~ 750 МБ, сжатый).

+2

В качестве отложенного '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/ имеет меньшее количество оговорок. –

+2

(Напротив, 'pipefail' - это, как правило, хорошая идея, когда у вас есть конкретный случай, когда вы хотите разрешить компонент конвейера сбой, вы можете разрешить это явно, для этого случая: var = $ ({zcat file. gz || :;} | head -n 12) 'будет делать). –

+2

... в сторону: нижний регистр 'var' правильный; см. [спецификацию переменной среды POSIX] (http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html): имена всех крышек используются переменными со значением для оболочки или системы; Имена нижнего регистра зарезервированы для использования приложения. Это относится и к неэкспортированным переменным оболочки, так как установка переменной оболочки будет перезаписывать любую переменную среды с похожим именем. –

ответ

8

Подумайте об этом, на мгновение.

  1. Вы сообщаете оболочке, что весь ваш конвейер должен считаться неудачным, если какой-либо компонент вышел из строя.
  2. Вы говорите zcat, чтобы записать свой вывод в head.
  3. Затем вы сообщаете head для выхода после чтения 12 строк из потока входного потока с гораздо большей длиной, чем 12 строк.

Из конечно у вас есть ошибка: zcat имеет свой трубопровод назначения закрыты рано, и был не в состоянии успешно написать распакованную версию входного файла! У него нет никакого способа узнать, что это было связано с намерением пользователя, через что-то ошибочное.

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


Специфическая ошибка, которая zcat уделяется операционной системой EPIPE, возвращаемая write системного вызова при следующих условиях: Сделана попытка записать в канал, который не открыт для чтения с помощью любого обработать.

После head (единственный читатель этого FIFO) завершился, для любой записи на входной стороне трубопровода не вернуть EPIPE будет ошибка. Для zcat, чтобы молча игнорировать ошибку, записывая свой вывод, и, таким образом, иметь возможность генерировать неточный выходной поток без статуса выхода, отражающего это событие, будет аналогичным образом быть ошибкой.


Если вы не хотите, чтобы изменить какие-либо из ваших вариантов оболочки, кстати, один обходной путь можно рассмотреть с помощью процесса замещения:

var=$(head -n 12 < <(zcat file.gz)) 

В этом случае zcat не компонент трубопровода и его статус выхода не рассматриваются для целей определения успеха. (Вы можете проверить, является ли $var длиной 12 строк, если вы хотите найти независимое определение успеха/отказа).

+1

Отличный ответ! Спасибо за детали. Хотя эти вещи могут быть очевидны для обученного компьютерного программиста или очень опытного кодера, есть много, многие люди, которые пишут сценарии и код, которые не являются компьютерными учеными, а также многие из нас являются самоучками. Реальность такова, что многие из нас, любителей, не имеют времени или даже знания о том, как * копаться во внутренней работе bash, труб, потоков, системных вызовов и т. Д. Когда вы не понимаете тонких деталей потоков, «писать» и т. д., это понятно из чистого воображения), что 'head' правильно завершает поток. – cmo

Смежные вопросы