Como posso consertar um erro de Broken Pipe?

31

Eu recentemente reinstalei o RVM (seguindo as instruções no link ) após uma nova instalação do Ubuntu 12.10 quando recebi um SSD Drive.

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 repito imediatamente o comando, só recebo:

rvm is a function

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

    
por Jason Shultz 20.02.2013 / 16:29

3 respostas

51

Ver "Broken pipe" nesta situação é raro, mas normal.

Quando você executa type rvm | head -1 , o bash executa type rvm em um processo, head -1 em outro. 1 O stdout de type está conectado ao final "write" de um < em> pipe , o stdin de head para o final "read". Ambos os processos são executados ao mesmo tempo.

O processo head -1 lê dados de stdin (normalmente em blocos de 8 kB), imprime uma única linha (de acordo com a opção -1 ) e sai, fazendo com que a extremidade "lida" do tubo seja fechadas. Como a função rvm é bastante longa (cerca de 11 kB depois de ser analisada e reconstruída por bash), isso significa que head sai enquanto type ainda tem alguns kB de dados para gravar.

Neste ponto, como type está tentando gravar em um pipe cuja outra extremidade foi fechada - um canal quebrado - a função write () chamada retornará um erro EPIPE, traduzido como "cano 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, já que a maioria dos usuários não quer que o primeiro processo continue rodando e tentando gravar para lugar algum. Enquanto isso, serviços não interativos ignoram o SIGPIPE - não seria bom para um longo executando o daemon para morrer em um erro tão simples - então eles acham o código de erro muito útil.)

No entanto, a entrega de sinal não é 100% imediata, e pode haver casos em que write () retorna EPIPE e o processo continua a funcionar por um curto período antes de receber o sinal. Nesse caso, type tem tempo suficiente para perceber a falha na gravação, traduzir o código de erro e até mesmo imprimir uma mensagem de erro para 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, já que o processo type e o código de entrega do sinal do kernel podem ser executados em diferentes núcleos, literalmente ao mesmo tempo.

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

No entanto, não é nada para se preocupar, e não está relacionado à sua instalação rvm de qualquer forma.

    
por 20.02.2013 / 17:39
22

Você pode corrigir um canal quebrado às custas de outro processo inserindo tail -n +1 em seu canal, assim:

type rvm | tail -n +1 | head -1

O +1 informa tail para imprimir a primeira linha de entrada e tudo o que segue. A saída será exatamente igual a se tail -n +1 não estava lá, mas o programa é inteligente o suficiente para verificar a saída padrão e fechar o tubo corretamente. Não há mais canais quebrados .

    
por 09.09.2013 / 15:59
2

A mensagem write error: Broken pipe refere-se a um processo de gravação que tenta gravar em um pipe sem nenhum leitor na extremidade de leitura daquele pipe e a circunstância especial de que o sinal SIGPIPE esteja definido para ser ignorado pela corrente ou o processo pai. Se foi o processo pai que definiu SIGPIPE para ser ignorado, não é possível que o processo filho desfaça isso novamente em um shell não-interacitivo.

No entanto, é possível matar type rvm quando head -1 termina usando subshells explícitos. Dessa forma, podemos usar o plano de fundo type rvm , enviar typepid para a subcamada head -1 e implementar uma interceptação em EXIT para matar type rvm explicitamente.

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)
    
por 07.04.2016 / 20:43