Como posso corrigir um erro de tubo quebrado?

36

Eu reinstalei recentemente o RVM (seguindo as instruções em http://rvm.io ) após uma nova instalação do Ubuntu 12.10 quando obtive uma unidade SSD.

Agora, quando eu digito: type rvm | head -1

Eu recebo o seguinte erro:

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

Mas se eu repetir imediatamente o comando, só recebo:

rvm is a function

E parece que está tudo bem? O que está acontecendo? O que posso fazer para corrigi-lo? Isso nem sempre acontece. Parece ser mais esporádico. Eu tentei encontrar algum tipo de padrão, mas ainda não o encontrei.

Jason Shultz
fonte

Respostas:

57

Ver "Tubo quebrado" nessa situação é raro, mas normal.

Quando você executa type rvm | head -1, o bash é executado type rvmem um processo, head -1em outro. 1 O stdout de typeestá conectado à extremidade "write" de um pipe , o stdout da extremidade head"read". Ambos os processos são executados ao mesmo tempo.

O head -1processo lê os dados do stdin (geralmente em pedaços de 8 kB), imprime uma única linha (de acordo com a -1opção) e sai, fazendo com que a extremidade "lida" do tubo seja fechada. Como a rvmfunção é bastante longa (cerca de 11 kB após ser analisada e reconstruída pelo bash), isso significa que headsai enquanto typeainda há alguns kB de dados para gravar.

Neste ponto, como typeestá tentando gravar em um pipe cuja outra extremidade foi fechada - um pipe quebrado - a função write () que ele chamou retornará um erro EPIPE, traduzido como "Pipe quebrado". Além desse erro, o kernel também envia o sinal SIGPIPE para type, que por padrão mata o processo imediatamente.

(O sinal é muito útil em shells interativos, pois a maioria dos usuários não deseja que o primeiro processo continue em execução e tente gravar em lugar nenhum. Enquanto isso, serviços não interativos ignoram o SIGPIPE - não seria bom para um daemon de longa execução morrem com um erro tão simples - para que eles achem o código de erro muito útil.)

No entanto, a entrega do sinal não é 100% imediata e pode haver casos em que write () retorne o EPIPE e o processo continue em execução por um curto período de tempo antes de receber o sinal. Nesse caso, typeobtém tempo suficiente para observar a falha na gravação, traduzir o código de erro e até imprimir uma mensagem de erro no stderr antes de ser morto pelo SIGPIPE. (A mensagem de erro diz "-bash: type:", pois typeé um comando interno do próprio bash.)

Isso parece ser mais comum em sistemas com várias CPUs, pois o typeprocesso e o código de entrega de sinal do kernel podem ser executados em núcleos diferentes, literalmente ao mesmo tempo.

Seria possível remover esta mensagem typecorrigindo o código interno (no código-fonte do bash) para sair imediatamente quando receber um EPIPE da função write ().

No entanto, não há com o que se preocupar e não está relacionado à sua rvminstalação de forma alguma.

gravidade
fonte
Obrigado! Eu estava preocupado com isso. Ontem à noite, pesquisei no Google por uma noite pesquisando defeitos a instalação do rvm e fazendo reparos tentando consertá-lo. Acabei de trocar com uma unidade SSD e usar o LVM e criptografar o disco rígido para que houvesse muitas variáveis ​​entrando em jogo e eu não tinha certeza do que poderia ter acontecido de lado. Obrigado por deixar minha mente à vontade!
Jason Shultz
I foram canalizando a saída de lsmeio head -1por anos, e hoje eu estou recebendo uma mensagem de tubulação quebrada.
Tulains Córdova
11
(Nota: O erro "cano quebrado" não vem a partir do sinal Ela vem do. Errno Enquanto o shell caso contrário pode mostrar mensagens de texto para induzida por sinal-saídas, é suficiente geralmente inteligente para fingir que uma saída SIGPIPE era um. 'clean' one.)
grawity
23

Você pode consertar um tubo quebrado às custas de outro processo , inserindo tail -n +1-o, assim:

tipo rvm | cauda -n +1 | cabeça -1

O +1diz tailpara imprimir a primeira linha de entrada e tudo o que se segue. A saída será exatamente igual à que tail -n +1não existia, mas o programa é inteligente o suficiente para verificar a saída padrão e fechar o tubo de maneira limpa. Chega de canos quebrados .

Huuu
fonte
11
Bom truque. Eu usei em uma situação diferente da fornecida aqui. Obrigado!
Alguém ainda usa o MS-DOS
6
Parecia uma ótima solução, mas no Ubuntu 14.04.2 com tail 8.21 eu recebo "tail: write error: Broken pipe", o que não é uma melhoria.
Roger Dueck
2
@RogerDueck está correto. Eu também vejo isso em um sistema Mandriva para um tipo semelhante de problema que find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | headproduz de forma confiável xargs: ls: terminated by signal 13. Como sabemos, o problema é de exaustão de entrada e há realmente apenas um comando que lida com o buffer: dd. A adição | dd obs=1Mao pipeline corrige o SIGPIPE para o meu caso de uso.
Andrew Beals
3
Vou alterar ainda mais a minha sugestão, embora eu vai notar que eu não acredito que xargs ou tipo deve ser kvetching sobre SIGPIPE, a esta: type rvm | (head -1 ; dd of=/dev/null) Isto, naturalmente, é semelhante a outras sugestões, uma vez que está causando toda a entrada a ser processado , mas dddeve ser o programa mais eficiente para lidar com essas coisas.
Andrew Beals 27/05
3
Comentário sobre os violadores do SIGPIPE aqui: mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html
Andrew Beals
2

A write error: Broken pipemensagem refere-se a um processo de gravação que tenta gravar em um canal sem nenhum leitor deixado na extremidade de leitura desse canal e a circunstância especial de que o SIGPIPEsinal está configurado para ser ignorado pelo processo atual ou pelo processo pai. Se foi o processo pai que configurou SIGPIPEpara ser ignorado, não é possível que o processo filho desfaça isso novamente em um shell não interativo.

No entanto, é possível eliminar type rvmquando head -1termina usando subcascas explícitas. Dessa forma, podemos fazer o segundo plano type rvm, enviar typepidpara o head -1subshell e implementar uma armadilha EXITpara matar type rvmexplicitamente.

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
fonte
Da resposta do grawity: typeobtém tempo suficiente para observar a falha na gravação, traduzir o código de erro e até imprimir uma mensagem de erro no stderr antes de ser morto pelo SIGPIPE . Acho que sua solução não impede que o processo produtor ( typeaqui) reaja à falha na gravação (devido ao tubo fechado), não é?
Piotr Dobrogost