Jak mogę naprawić błąd Broken Pipe?


36

Niedawno ponownie zainstalowałem RVM (postępując zgodnie z instrukcjami na http://rvm.io ) po nowej instalacji Ubuntu 12.10, kiedy dostałem dysk SSD.

Teraz, kiedy piszę: type rvm | head -1

Otrzymuję następujący błąd:

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

Ale jeśli natychmiast powtórzę polecenie, otrzymam tylko:

rvm is a function

I wygląda na to, że wszystko jest w porządku? Co się dzieje? Co mogę zrobić, aby to naprawić? Nie zawsze tak się dzieje. Wydaje się być bardziej sporadyczny. Próbowałem znaleźć jakiś wzór, ale jeszcze tego nie zrobiłem.

Odpowiedzi:


57

Widzenie „Broken pipe” w tej sytuacji jest rzadkie, ale normalne.

Po uruchomieniu type rvm | head -1bash wykonuje się type rvmw jednym procesie, head -1w innym. 1 Stdout typejest podłączony do końca „zapisu” potoku , a stdin headdo końca „odczytu”. Oba procesy działają w tym samym czasie.

head -1Proces odczytuje dane ze standardowego wejścia (zwykle kawałki 8 KB) drukuje jednej linii (w zależności od -1wariantu) i wyjścia, co powoduje „Czytaj” koniec rury, która ma być zamknięty. Ponieważ rvmfunkcja jest dość długa (około 11 kB po przeanalizowaniu i zrekonstruowaniu przez bash), oznacza to, że headkończy działanie, typewciąż mając kilka kB danych do zapisania.

W tym momencie, ponieważ typepróbuje napisać do potoku, którego drugi koniec został zamknięty - zepsuty potok - funkcja write (), którą skalował, zwróci błąd EPIPE, przetłumaczony jako „zepsuty potok”. Oprócz tego błędu jądro wysyła również sygnał SIGPIPE type, który domyślnie zabija proces natychmiast.

(Sygnał jest bardzo przydatny w interaktywnych powłokach, ponieważ większość użytkowników nie chce, aby pierwszy proces działał dalej i próbował pisać do nikąd. Tymczasem usługi nieinteraktywne ignorują SIGPIPE - nie byłoby dobrze, aby długo działający demon umierają na tak prosty błąd - dlatego uważają, że kod błędu jest bardzo przydatny).

Jednak dostarczanie sygnału nie jest w 100% natychmiastowe i mogą wystąpić przypadki, gdy write () zwraca EPIPE, a proces kontynuuje działanie przez krótką chwilę przed otrzymaniem sygnału. W takim przypadku typedostaje wystarczająco dużo czasu, aby zauważyć nieudany zapis, przetłumaczyć kod błędu, a nawet wydrukować komunikat o błędzie do stderr, zanim zostanie zabity przez SIGPIPE. (Komunikat o błędzie brzmi „-bash: type:”, ponieważ typejest to wbudowane polecenie samego basha.)

Wydaje się, że jest to bardziej powszechne w systemach wieloprocesorowych, ponieważ typeproces i kod dostarczania sygnału jądra mogą działać na różnych rdzeniach, dosłownie w tym samym czasie.

Byłoby możliwe usunięcie tego komunikatu przez załatanie typewbudowanego (w kodzie źródłowym bash), aby natychmiast wyjść, gdy otrzyma EPIPE z funkcji write ().

Nie należy się jednak tym przejmować i nie ma to żadnego związku z rvminstalacją.


Dziękuję Ci! Martwiłem się tym. Wczoraj wieczorem zrobiłem około godziny googlingu, szukając rozwiązania mojej instalacji RVM i naprawiając go, próbując go naprawić. Właśnie wymieniłem się dyskiem SSD i korzystałem z LVM i zaszyfrowałem dysk twardy, więc w grę wchodziło wiele zmiennych i po prostu nie byłem pewien, co mogło pójść na bok. Dziękuję za uspokojenie mojego umysłu!
Jason Shultz

Przesyłam dane wyjściowe lsprzez head -1lata, a dziś otrzymuję komunikat zepsutej rury.
Tulains Córdova

1
(Uwaga: błąd „Broken pipe” nie pochodzi z sygnału. Pochodzi z errno . Podczas gdy powłoka może w przeciwnym razie wyświetlać wiadomości tekstowe dla wyjść indukowanych sygnałem, zwykle jest wystarczająco mądra, aby udawać, że wyjście SIGPIPE było „czysty”).
grawity

23

Możesz naprawić zepsutą rurę kosztem innego procesu , wstawiając tail -n +1do niej rurkę w następujący sposób:

wpisz rvm | ogon -n +1 | głowa -1

+1Mówi taildo wydrukowania pierwszej linii wejścia i wszystkiego, co następuje. Dane wyjściowe będą dokładnie takie same, jak gdyby ich tail -n +1nie było, ale program jest wystarczająco inteligentny, aby sprawdzić standardowe dane wyjściowe i dokładnie zamyka potok. Nigdy więcej połamanych rur .


1
Niezła sztuczka. Użyłem w innej sytuacji niż tutaj. Dzięki!
Ktoś nadal cię używa MS-DOS

6
Wyglądało to na świetne rozwiązanie, ale na Ubuntu 14.04.2 z ogonem 8.21 pojawia się „ogon: błąd zapisu: zepsuta rura”, co nie jest poprawą.
Roger Dueck,

2
@RogerDueck jest poprawny. Widzę to również w systemie Mandriva dla podobnego rodzaju problemu, który find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | headniezawodnie daje xargs: ls: terminated by signal 13. Jak wiemy, problemem jest wyczerpanie danych wejściowych i tak naprawdę tylko jedno polecenie zajmuje się buforowaniem: dd. Dodanie | dd obs=1Mdo potoku naprawia SIGPIPE dla mojego przypadku użycia.
Andrew Beals,

3
Będę dalej poprawiać moją sugestię, chociaż zauważę, że nie wierzę, że xargs lub typ powinny kvetchować o SIGPIPE, do tego: type rvm | (head -1 ; dd of=/dev/null) To, oczywiście, jest podobne do innych sugestii, ponieważ powoduje przetwarzanie wszystkich danych wejściowych , ale ddpowinien być najbardziej wydajnym programem do obsługi takich rzeczy.
Andrew Beals

3
Komentarz na temat osób naruszających SIGPIPE tutaj: mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html
Andrew Beals

2

write error: Broken pipeWiadomość odnosi się do procesu pisania, który próbuje pisać do potoku bez pozostawionych na koniec czytania tej rury i szczególną okoliczność, że czytelników SIGPIPEsygnał ma zostać zignorowany albo przez prąd lub procesu macierzystego. Jeśli był to proces nadrzędny, który SIGPIPEzostał zignorowany, proces podrzędny nie może go cofnąć ponownie w powłoce nieinterakcyjnej.

Możliwe jest jednak zabijanie type rvmpo head -1zakończeniu przy użyciu jawnych podpowłok. W ten sposób możemy w tle type rvm, wysłać typepiddo head -1podpowłoki, a następnie zaimplementować tam pułapkę, EXITaby type rvmjawnie zabić .

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)

Z odpowiedzi grawity: typedostaje wystarczająco dużo czasu, aby zauważyć nieudany zapis, przetłumaczyć kod błędu, a nawet wydrukować komunikat o błędzie do stderr, zanim zostanie zabity przez SIGPIPE . Myślę, że twoje rozwiązanie nie zapobiega reakcji producenta ( typetutaj) na nieudany zapis (z powodu zamkniętego potoku), prawda?
Piotr Dobrogost
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.