¿Cómo puedo solucionar un error de tubería rota?

36

Recientemente reinstalé RVM (siguiendo las instrucciones en http://rvm.io ) después de una nueva instalación de Ubuntu 12.10 cuando obtuve una unidad SSD.

Ahora, cuando escribo: type rvm | head -1

Recibo el siguiente error:

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

Pero si repito inmediatamente el comando, solo recibo:

rvm is a function

¿Y parece que todo está bien? ¿Qué esta pasando? ¿Que puedo hacer para arreglarlo? No pasa siempre. Parece ser más esporádico. He tratado de encontrar algún tipo de patrón, pero aún no lo he hecho.

Jason Shultz
fuente

Respuestas:

57

Ver "tubería rota" en esta situación es raro, pero normal.

Cuando ejecuta type rvm | head -1, bash se ejecuta type rvmen un proceso, head -1en otro. 1 El stdout de typeestá conectado al extremo de "escritura" de una tubería , el stdin de headal extremo de "lectura". Ambos procesos se ejecutan al mismo tiempo.

El head -1proceso lee los datos de la entrada estándar (generalmente en fragmentos de 8 kB), imprime una sola línea (según la -1opción) y sale, haciendo que se cierre el extremo "leído" de la tubería. Dado que la rvmfunción es bastante larga (alrededor de 11 kB después de ser analizada y reconstruida por bash), esto significa que las headsalidas typeaún tienen unos pocos kB de datos para escribir.

En este punto, dado que typeestá intentando escribir en una tubería cuyo otro extremo se ha cerrado (una tubería rota ), la función write () que solicitó devolverá un error EPIPE, traducido como "tubería rota". Además de este error, el núcleo también envía la señal SIGPIPE a type, que por defecto mata el proceso de inmediato.

(La señal es muy útil en shells interactivos, ya que la mayoría de los usuarios no quieren que el primer proceso continúe ejecutándose e intenten escribir en ninguna parte. Mientras tanto, los servicios no interactivos ignoran SIGPIPE; no sería bueno para un demonio de larga ejecución). morir en un error tan simple, por lo que encuentran el código de error muy útil).

Sin embargo, la entrega de la señal no es 100% inmediata, y puede haber casos en los que write () devuelve EPIPE y el proceso continúa ejecutándose por un corto tiempo antes de recibir la señal. En este caso, typeobtiene suficiente tiempo para notar la escritura fallida, traducir el código de error e incluso imprimir un mensaje de error en stderr antes de que SIGPIPE lo elimine. (El mensaje de error dice "-bash: type:" ya que typees un comando incorporado de bash).

Esto parece ser más común en sistemas con múltiples CPU, ya que el typeproceso y el código de entrega de señal del núcleo pueden ejecutarse en diferentes núcleos, literalmente al mismo tiempo.

Sería posible eliminar este mensaje parcheando el typeincorporado (en el código fuente de bash) para salir inmediatamente cuando recibe un EPIPE de la función write ().

Sin embargo, no hay nada de qué preocuparse, y no está relacionado con su rvminstalación de ninguna manera.

Gravedad
fuente
¡Gracias! Estaba preocupado por eso. Ayer por la noche busqué en Google una hora para solucionar problemas de la instalación de mi rvm y hacer reparaciones para solucionarlo. Acababa de cambiarme por una unidad SSD y usaba LVM y encriptaba el disco duro para que entraran en juego muchas variables y no estaba seguro de qué podría haber sido de lado. ¡Gracias por tranquilizarme!
Jason Shultz
He estado tubería de la salida del lsmedio head -1de años, y hoy estoy recibiendo un mensaje tubería rota.
Tulains Córdova
1
(Nota: El error "Tubo roto" no viene de la señal que proviene de la. Errno Mientras que la cáscara de lo contrario puede mostrar mensajes de texto para inducida por señal-salidas, es lo suficientemente general inteligentes pretender que una salida SIGPIPE era una. 'clean' one.)
grawity
23

Puede arreglar una tubería rota a expensas de otro proceso insertando tail -n +1en su tubería, de esta manera:

tipo rvm | cola -n +1 | cabeza -1

El +1le dice tailque imprima la primera línea de entrada y todo lo que sigue. La salida será exactamente la misma que si tail -n +1no estuviera allí, pero el programa es lo suficientemente inteligente como para verificar la salida estándar y cierra la tubería limpiamente. No más tuberías rotas .

Huuu
fuente
1
Buen truco. Lo he usado en una situación diferente a la que se proporciona aquí. ¡Gracias!
Alguien todavía te usa MS-DOS el
66
Parecía una gran solución, pero en Ubuntu 14.04.2 con cola 8.21 me sale "cola: error de escritura: tubería rota", lo que no mejora.
Roger Dueck
2
@RogerDueck es correcto. También veo esto en un sistema Mandriva para un tipo similar de problema que find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | headrinde de manera confiable xargs: ls: terminated by signal 13. Como sabemos, el problema es el agotamiento de la entrada y en realidad solo hay un comando que se ocupa del almacenamiento en búfer: dd. Agregar | dd obs=1Ma la tubería corrige el SIGPIPE para mi caso de uso.
Andrew Beals
3
Enmendaré aún más mi sugerencia, aunque notaré que no creo que los xargs o el tipo de información se debaten a SIGPIPE, a esto: type rvm | (head -1 ; dd of=/dev/null) Esto, por supuesto, es similar a otras sugerencias ya que está causando que se procesen todas las entradas. , pero dddebería ser el programa más eficiente para manejar tales cosas.
Andrew Beals
3
Comentario sobre los infractores de SIGPIPE aquí: mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html
Andrew Beals
2

El write error: Broken pipemensaje se refiere a un proceso de escritura que intenta escribir en una tubería sin lectores en el extremo de lectura de esa tubería y la circunstancia especial de que la SIGPIPEseñal está configurada para ser ignorada por el proceso actual o el proceso principal. Si fue el proceso padre el que se configuró SIGPIPEpara ser ignorado, no es posible que el proceso hijo lo deshaga nuevamente en un shell no interactivo.

Sin embargo, es posible matar type rvmcuando head -1termina utilizando subcapas explícitas. De esta forma podemos hacer un fondo type rvm, enviar typepida la head -1subshell y luego implementar una trampa EXITallí para matar type rvmexplícitamente.

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
fuente
De la respuesta de Grawity: typeobtiene el tiempo suficiente para notar la escritura fallida, traduce el código de error e incluso imprime un mensaje de error en stderr antes de ser asesinado por SIGPIPE . Creo que su solución no impide que el proceso del productor ( typeaquí) reaccione a la escritura fallida (debido a una tubería cerrada), ¿verdad?
Piotr Dobrogost