Come posso correggere un errore di tubo rotto?


36

Di recente ho reinstallato RVM (seguendo le istruzioni su http://rvm.io ) dopo una nuova installazione di Ubuntu 12.10 quando ho ottenuto un'unità SSD.

Ora, quando scrivo: type rvm | head -1

Ricevo il seguente errore:

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

Ma se ripeto immediatamente il comando, ricevo solo:

rvm is a function

E sembra tutto a posto? Cosa sta succedendo? Cosa posso fare per risolverlo? Non succede sempre. Sembra essere più sporadico. Ho provato a trovare una specie di modello ma non l'ho ancora fatto.

Risposte:


57

Vedere "tubo rotto" in questa situazione è raro, ma normale.

Quando esegui type rvm | head -1, bash viene eseguito type rvmin un processo, head -1in un altro. 1 Lo stdout di typeè collegato all'estremità "write" di una pipe , lo stdin of headall'estremità "read". Entrambi i processi vengono eseguiti contemporaneamente.

Il head -1processo legge i dati dallo stdin (di solito in blocchi di 8 kB), stampa una singola riga (secondo l' -1opzione) ed esce, causando la chiusura dell'estremità "read" del tubo. Poiché la rvmfunzione è piuttosto lunga (circa 11 kB dopo essere stata analizzata e ricostruita da bash), ciò significa che headesce mentre typeha ancora pochi kB di dati da scrivere.

A questo punto, poiché typesta provando a scrivere su una pipe la cui altra estremità è stata chiusa - una pipe rotta - la funzione write () che ha richiamato restituirà un errore EPIPE, tradotto come "Broken pipe". Oltre a questo errore, il kernel invia anche il segnale SIGPIPE type, che di default uccide immediatamente il processo.

(Il segnale è molto utile nelle shell interattive, dal momento che la maggior parte degli utenti non vuole che il primo processo continui a funzionare e che tenti di scrivere da nessuna parte. Nel frattempo, i servizi non interattivi ignorano SIGPIPE - non sarebbe utile per un demone di lunga durata muoiono per un errore così semplice - quindi trovano molto utile il codice di errore.)

Tuttavia, l'erogazione del segnale non è immediata al 100% e potrebbero verificarsi casi in cui write () restituisce EPIPE e il processo continua a essere eseguito per un breve periodo prima di ricevere il segnale. In questo caso, typeottiene abbastanza tempo per notare la scrittura non riuscita, tradurre il codice di errore e persino stampare un messaggio di errore su stderr prima di essere ucciso da SIGPIPE. (Il messaggio di errore dice "-bash: type:" poiché typeè un comando incorporato di bash stesso.)

Questo sembra essere più comune sui sistemi multi-CPU, poiché il typeprocesso e il codice di consegna del segnale del kernel possono essere eseguiti su core diversi, letteralmente allo stesso tempo.

Sarebbe possibile rimuovere questo messaggio correggendo il typebuiltin (nel codice sorgente di bash) per uscire immediatamente quando riceve un EPIPE dalla funzione write ().

Tuttavia, non è nulla di cui preoccuparsi e non è rvmin alcun modo correlato alla propria installazione.


Grazie! Ero preoccupato per questo. La scorsa notte ho fatto una ricerca su Google per circa un'ora, risolvendo i problemi con la mia installazione di rvm e facendo riparazioni cercando di risolverlo. Avevo appena cambiato con un disco SSD e usato LVM e crittografato il disco rigido, quindi c'erano molte variabili in gioco e non ero sicuro di cosa sarebbe potuto andare lateralmente. Grazie per avermi messo a mio agio!
Jason Shultz,

Ho convogliato l'output di lsthrough head -1per anni e oggi ricevo un messaggio di pipe non funzionante.
Tulains Córdova,

1
(Nota: L'errore "tubo rotto" non viene dal segnale Proviene dalla. Errno mentre il guscio può altrimenti visualizzare i messaggi di testo per il segnale indotta-uscite, è di solito abbastanza intelligente per far finta che un'uscita SIGPIPE era una. "pulito".)
Grawity

23

Puoi riparare un tubo rotto a spese di un altro processo inserendolo tail -n +1nel tuo tubo, in questo modo:

digitare rvm | coda -n +1 | testa -1

Il +1dice taildi stampare la prima riga di input e tutto ciò che segue. L'output sarà esattamente lo stesso di se tail -n +1non ci fosse, ma il programma è abbastanza intelligente da controllare l'output standard e chiudere il tubo in modo pulito. Niente più tubi rotti .


1
Bel trucco. Ho usato in una situazione diversa da quella fornita qui. Grazie!
Qualcuno usa ancora il tuo MS-DOS il

6
Sembrava un'ottima soluzione, ma su Ubuntu 14.04.2 con coda 8.21 ottengo "coda: errore di scrittura: tubo rotto", che non è un miglioramento.
Roger Dueck,

2
@RogerDueck è corretto. Vedo anche questo su un sistema Mandriva per un simile tipo di problema che find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | headgenera in modo affidabile xargs: ls: terminated by signal 13. Come sappiamo, il problema è quello dell'esaurimento dell'input e c'è davvero un solo comando che si occupa del buffering: dd. L'aggiunta | dd obs=1Malla pipeline corregge SIGPIPE per il mio caso d'uso.
Andrew Beals,

3
Modificherò ulteriormente il mio suggerimento, anche se noterò che non credo che xargs o type dovrebbero essere kvetching su SIGPIPE, a questo: type rvm | (head -1 ; dd of=/dev/null) questo, ovviamente, è simile ad altri suggerimenti in quanto sta causando l'elaborazione di tutti gli input , ma dddovrebbe essere il programma più efficiente per gestire tali cose.
Andrew Beals,


2

Il write error: Broken pipemessaggio si riferisce a un processo di scrittura che tenta di scrivere su una pipe senza lettori rimasti sull'estremità di lettura di quella pipe e la circostanza speciale che il SIGPIPEsegnale è impostato per essere ignorato dal processo corrente o padre. Se era il processo genitore impostato SIGPIPEper essere ignorato, non è possibile per il processo figlio annullarlo nuovamente in una shell non interattiva.

Tuttavia, è possibile uccidere type rvmquando head -1termina utilizzando sottotitoli espliciti. In questo modo possiamo mettere in background type rvm, inviare typepidalla head -1subshell e quindi implementare una trappola EXITlì per uccidere type rvmesplicitamente.

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)

Dalla risposta di Grawity: typeottiene abbastanza tempo per notare la scrittura non riuscita, tradurre il codice di errore e persino stampare un messaggio di errore su stderr prima di essere ucciso da SIGPIPE . Penso che la tua soluzione non impedisca al processo del produttore ( typequi) di reagire alla scrittura fallita (a causa di un tubo chiuso), vero?
Piotr Dobrogost,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.