Script Bash 'while read' loop causa erro 'broken pipe' quando executado com o GNU Parallel

2

De acordo com a lista de discussão GNU Parallel, este não é um problema específico do GNU Parallel. Eles sugeriram que eu publicasse meu problema aqui.

O erro que estou recebendo é um erro de "canal quebrado", mas acho que primeiro devo explicar o contexto do meu problema e o que causa esse erro. Isso acontece quando se tenta usar qualquer script bash contendo um loop 'while read' no GNU Parallel.

Eu tenho um script bash básico como este:

#!/bin/bash
# linkcheck.sh

while read domain
do
host "$domain"
done

Suponha que eu queira canalizar em uma lista grande (digamos 250 MB).

cat urllist | ./linkcheck.sh

A execução do comando do host em 250 MB de URLs é bastante lenta. Para acelerar as coisas, quero dividir a entrada em partes antes de fazer a tubulação e, em seguida, executar vários trabalhos em paralelo. O GNU Parallel é capaz de fazer isso.

cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}

{} é substituído pelo conteúdo do urllist linha por linha. Suponha que a configuração padrão dos meus sistemas seja capaz de executar 500 jobs por instância de paralela. Para contornar essa limitação, podemos paralelizar o próprio Parallel:

cat urllist | parallel -j10 --pipe parallel -j0 ./linkcheck.sh {}

Isso executará 5000 postos de trabalho. Ele também, infelizmente, causará o erro "broken pipe" ( (bash FAQ) . No entanto, o script começa a funcionar se eu remover o loop de leitura while e receber informações diretamente de qualquer coisa enviada para {}, por exemplo,

#!/bin/bash
# linkchecker.sh

domain="$1"
host "$1"

Por que não funcionará com um loop de leitura? É seguro desligar o sinal SIGPIPE para interromper a mensagem "broken pipe" ou os efeitos colaterais, como corrupção de dados?

Obrigado pela leitura.

    
por Joe White 28.09.2012 / 00:35

2 respostas

1

Então, fizemos

cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}

funciona corretamente? Eu acredito que parte do seu problema pode ser que você deixou de fora o segundo --pipe , como em

cat urllist | parallel -j10 --pipe parallel -j0 --pipe ./linkcheck.sh {}

BTW, você nunca precisa dizer

cat one_file | some_command

Você sempre pode alterar isso para

some_command < one_file

resultando em um processo a menos (e um tubo a menos). (Pode ser apropriado / necessário usar cat quando você tiver vários arquivos de entrada.)

    
por 28.09.2012 / 01:23
0

Parece-me que o erro pode estar ocorrendo devido a uma condição de corrida ruim por causa da janela entre bifurcar um filho para executar outra cópia do linkcheck.sh enquanto o pipe ainda está aberto e quando a criança realmente tenta ler. Nessa janela, outra cópia leu EOF e o canal foi fechado.

    
por 28.09.2012 / 00:47