Как я могу исправить ошибку Broken Pipe?

36

Я недавно переустановил RVM (следуя инструкциям на http://rvm.io ) после новой установки Ubuntu 12.10, когда я получил SSD-диск.

Теперь, когда я печатаю: type rvm | head -1

Я получаю следующую ошибку:

rvm is a function
-bash: type: write error: Broken pipe

Но если я немедленно повторю команду, то получу только:

rvm is a function

И, кажется, все в порядке? Что творится? Что я могу сделать, чтобы это исправить? Так не бывает всегда. Это кажется более спорадическим. Я пытался найти какую-то модель, но пока не нашел.

Джейсон Шульц
источник

Ответы:

57

Видеть «Сломанную трубу» в этой ситуации редко, но нормально.

Когда вы запускаете type rvm | head -1, bash выполняется type rvmв одном процессе, head -1в другом. 1 стандартный вывод из typeподключен к «записи» конец трубы , то из стандартного ввода headк «читать» конец. Оба процесса выполняются одновременно.

head -1Процесс считывает данные из стандартного ввода (обычно в куски 8 КБ), вывести в одной строке ( в соответствии с -1параметром), и выходы, в результате чего «читать» конец трубы должен быть закрыт. Поскольку rvmфункция довольно длинная (около 11 кБ после анализа и восстановления bash), это означает, что headпри выходе typeвсе еще остается несколько кБ данных для записи.

На этом этапе, поскольку typeон пытается выполнить запись в канал, чей другой конец был закрыт - сломанный канал, - функция write (), которую он вызвал, вернет ошибку EPIPE, переведенную как «Broken pipe». В дополнение к этой ошибке ядро ​​также отправляет сигнал SIGPIPE type, который по умолчанию немедленно завершает процесс.

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

Однако доставка сигнала не происходит на 100% немедленно, и могут быть случаи, когда write () возвращает EPIPE, и процесс продолжает работать некоторое время до получения сигнала. В этом случае у вас typeбудет достаточно времени, чтобы заметить неудачную запись, перевести код ошибки и даже напечатать сообщение об ошибке в stderr, прежде чем SIGPIPE прекратит его. (В сообщении об ошибке указано «-bash: type:», поскольку typeэто встроенная команда самого bash.)

Похоже, что это чаще встречается в многопроцессорных системах, поскольку typeпроцесс и код доставки сигнала ядра могут работать на разных ядрах, буквально одновременно.

Можно было бы удалить это сообщение, исправив typeвстроенную функцию (в исходном коде bash) для немедленного выхода при получении EPIPE от функции write ().

Тем не менее, это не о чем беспокоиться, и это никак не связано с вашей rvmустановкой.

grawity
источник
Спасибо! Я беспокоился об этом. Прошлой ночью я потратил около часа на поиск и устранение неполадок, связанных с установкой rvm и ремонтом, пытаясь это исправить. Я просто поменял место на SSD-накопителе и использовал LVM и зашифровал жесткий диск, поэтому в игру вступило много переменных, и я просто не был уверен, что могло бы пойти не так. Спасибо, что успокоили мой разум!
Джейсон Шульц
Я уже несколько лет передаю результаты lsчерез head -1, и сегодня я получаю сообщение о сломанной трубе.
Тулаинс Кордова
1
(Примечание. Ошибка «Сломанная труба» не исходит из сигнала. Она происходит из-за ошибки . Хотя в противном случае оболочка может отображать текстовые сообщения для выходов, вызванных сигналом, она обычно достаточно умна, чтобы делать вид, что выход SIGPIPE был «чистый».)
grawity
23

Вы можете исправить сломанную трубу за счет другого процесса , вставив tail -n +1в свою трубу, например так:

Тип RVM | хвост -n +1 | голова -1

+1Говорит tailнапечатать первую строку ввода , и все , что следует. Вывод будет точно таким же, как если бы tail -n +1его не было, но программа достаточно умна, чтобы проверить стандартный вывод, и полностью закрывает канал. Нет больше сломанных труб .

Huuu
источник
1
Хороший трюк. Я использовал в другой ситуации, чем та, которая представлена ​​здесь. Благодарность!
Кто-то по-прежнему использует тебя MS-DOS
6
Выглядело как отличное решение, но в Ubuntu 14.04.2 с tail 8.21 я получаю сообщение «tail: write error: Broken pipe», которое не является улучшением.
Роджер Дуек
2
@RogerDueck правильно. Я также вижу это на системе Mandriva для подобного рода проблемы find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | headнадежно доходности xargs: ls: terminated by signal 13. Как мы знаем, проблема заключается в исчерпании ввода, и на самом деле только одна команда имеет дело с буферизацией: dd. Добавление | dd obs=1Mв конвейер исправляет SIGPIPE для моего варианта использования.
Эндрю Билс
3
Я внесу дальнейшие изменения в свое предложение, хотя и отмечу, что я не верю, что xargs или type должны упоминать SIGPIPE, так: type rvm | (head -1 ; dd of=/dev/null) это, конечно, похоже на другие предложения, поскольку вызывает обработку всего ввода , но ddдолжна быть самой эффективной программой для обработки таких вещей.
Эндрю Билс
3
Комментарий к нарушителям SIGPIPE здесь: mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html
Эндрю Билс
2

write error: Broken pipeСообщение относится к процессу письма , который пытается записать в трубу без каких - либо читателей , оставленных на конце чтения этой трубы и специального обстоятельство , что SIGPIPEсигнал установлен быть проигнорированы либо током или родительского процессом. Если это был родительский процесс, который SIGPIPEбыл проигнорирован, то дочерний процесс не может отменить это снова в неинтерактивной оболочке.

Тем не менее, можно завершить, type rvmкогда head -1завершается с помощью явных подоболочек. Таким образом, мы можем выполнить фон type rvm, отправить typepidв head -1подоболочку, а затем реализовать ловушку EXITдля type rvmявного уничтожения .

trap "" PIPE        # parent process sets SIGPIPE to be ignored
bash                # start child process
export LANG=C
# create a fake rvm function
eval "
rvm() {
$(printf 'echo line of rvm code %s\n' {1..10000})
}
"

# rvm is a function
# bash: type: write error: Broken pipe
type rvm | head -1

# kill type rvm when head -1 terminates
# sleep 0: do nothing but with external command
( (sleep 0; type rvm) & echo ${!} ; wait ${!} ) | 
    (trap 'trap - EXIT; kill "$typepid"; exit' EXIT; typepid="$(head -1)"; head -1)
zancox
источник
От ответа grawity: typeполучает достаточно времени, чтобы заметить неудачную запись, перевести код ошибки и даже напечатать сообщение об ошибке в stderr перед тем, как SIGPIPE уничтожит его . Я думаю, что ваше решение не мешает процессу производителя ( typeздесь) реагировать на неудачную запись (из-за закрытого канала), не так ли?
Петр Доброгост