Як я можу виправити помилку зі зламаною трубою?


36

Нещодавно я перевстановив RVM (слідуючи інструкціям на http://rvm.io ) після нової установки Ubuntu 12.10, коли отримав SSD Drive.

Тепер, коли я набираю: type rvm | head -1

Я отримую таку помилку:

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

Але якщо я негайно повторюю команду, я отримую лише:

rvm is a function

І, здається, все гаразд? Що відбувається? Що я можу зробити, щоб це виправити? Це трапляється не завжди. Це здається більш спорадичним. Я намагався знайти якийсь зразок до нього, але поки що не.

Відповіді:


57

Бачити "Розбиту трубу" в цій ситуації рідко, але нормально.

Під час запуску type rvm | head -1bash виконується type rvmв одному процесі, head -1в іншому. 1 Виділення typeз’єднане з кінцем труби "записувати" , а з head"зчитувати" - "зчитувати". Обидва процеси працюють одночасно.

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

З цього моменту, оскільки typeнамагається записати в трубу, інший кінець якої закритий - зламана труба - функція write (), яку вона викликала, поверне помилку EPIPE, перекладену як "Розбита труба". Крім цієї помилки, ядро ​​також передає сигнал SIGPIPE type, який за замовчуванням вбиває процес негайно.

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

Однак подача сигналу не є на 100% негайною, і можуть бути випадки, коли write () повертає EPIPE, і процес продовжує тривати ненадовго до отримання сигналу. У цьому випадку typeотримує достатньо часу, щоб помітити невдале записування, перекласти код помилки і навіть надрукувати повідомлення про помилку в stderr, перш ніж його вбити SIGPIPE. (Повідомлення про помилку говорить "-bash: type:" оскільки typeце сама вбудована команда bash.)

Це, мабуть, частіше зустрічається в системах з декількома процесорами, оскільки typeпроцес і код доставки сигналу ядра можуть працювати на різних ядрах, буквально одночасно.

Можна було б видалити це повідомлення, виправляючи typeвбудований (у вихідному коді bash) негайний вихід, коли він отримує EPIPE від функції write ().

Однак це нічого не турбує, і це rvmніяк не пов'язане з вашою установкою.


Дякую! Я хвилювався з цього приводу. Я вчора ввечері вирішив про неполадки в Google, щоб усунути мою установку rvm і зробити ремонт, намагаючись її виправити. Я просто обмінявся SSD-накопичувачем, використовував LVM і зашифрував жорсткий диск, тому в грі було багато змінних, і я просто не був впевнений, що може піти набік. Дякую, що розслабила мій погляд!
Джейсон Шульц

Я конвеєр від lsнаскрізного в head -1протягом багатьох років, і сьогодні я отримую повідомлення зламаною труби.
Tulains Córdova

1
(Примітка. Помилка "Зламана труба" не походить від сигналу. Походить від errno . Хоча оболонка в іншому випадку може відображати текстові повідомлення для викликаних сигналом виходів, зазвичай досить розумно зробити вигляд, що вихід SIGPIPE був 'чистий'.)
grawity

23

Ви можете виправити зламану трубу за рахунок іншого процесу , вставивши tail -n +1у неї трубу, наприклад:

тип rvm | хвіст -n +1 | голова -1

+1Каже tailнадрукувати перший рядок введення , і все , що треба. Вихід буде точно таким же, як якщо б tail -n +1його не було, але програма досить розумна, щоб перевірити стандартний вихід і чисто закрити трубу вниз. Більше не зламаних труб .


1
Гарний трюк. Я використовував ситуацію, що інша, ніж тут. Спасибі!
Хтось досі використовує вас MS-DOS

6
Це виглядало як чудове рішення, але на Ubuntu 14.04.2 з хвостом 8.21 я отримую "хвіст: помилка запису: Зламана труба", що не є поліпшенням.
Роджер Дуек

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
Ендрю Білз

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)

З відповіді grawity: typeотримує достатньо часу, щоб помітити невдале написання, перевести код помилки і навіть надрукувати повідомлення про помилку в stderr, перш ніж вбити SIGPIPE . Я думаю, що ваше рішення не заважає виробничому процесу ( typeтут) реагувати на помилку запису (через закриту трубу), чи не так?
Пьотр Доброгост
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.