bash: eco: erro de gravação: Chamada de sistema interrompida

9

Quero gerar uma lista classificada com todos os números de 8 dígitos - de 00000000 a 99999999. Digitei no shell:

f() {
 while IFS="" read -r line; do
   for i in {0..9}; do 
       echo "$line$i";
   done;
 done
}

echo | f | f | f | f | f | f | f | f | tee result.txt | wc -l

resposta é

bash: echo: write error: Interrupted system call
bash: echo: write error: Interrupted system call
bash: echo: write error: Interrupted system call
99998890

Por que recebi esses três erros e result.txt incorreto?

eu uso

Lançamento do GNU bash, versão 4.4.12 (1) (x86_64-pc-linux-gnu)

Debian GNU / Linux 9.6 (estiramento)

Kernel do Linux: 4.19.0 # 2 SMP Qui 1 nov 15:31:34 EET 2018 x86_64 GNU / Linux

hon
fonte
2
Não posso deixar de sentir que esse modo de fazê-lo não seria mais eficiente do que seq -w 0 99999999.
Kusalananda
1
Então a pergunta está incompleta / incorreta / mal escrita ou outra coisa. Porque o script (quando concluído com o }) funciona corretamente. @ GAD3R
Isaac
1
Nota: posso desencadear esses erros quase sob demanda. Eles costumam aparecer quando redimensiono minha konsolejanela. Esse redimensionamento é quase suficiente no meu caso, mas não é necessário.
Kamil Maciorowski
Posso remover o | tee result.txte ainda assim receber o erro.
CTRL-ALT-DELOR # 9/18
Outra observação: executável externo ( /bin/echono meu caso), em vez de echointerno, torna a função imune (ou pelo menos menos propensa) a esse problema.
Kamil Maciorowski

Respostas:

6

O write error: Interrupted system callerro específico é gerado quando o tamanho da janela do console é alterado enquanto o script está sendo executado.

Fazendo um:

 trap '' SIGWINCH

irá evitá-lo.

Observe que um

 seq 99999999 >result.txt; wc -l <result.txt

Será mais rápido e evitará o SIGWINCHproblema.

Isaac
fonte
5
Então, o que está acontecendo ?, por que eu não vi isso antes ?, Por que um erro de gravação é a coisa certa a fazer?
CTRL-ALT-DELOR # 9/18
4

Este é realmente um bug [1] em bash, e isso não acontece apenas em SIGWINCH, mas também em qualquer sinal de que uma armadilha foi definida:

{ pid=$BASHPID; trap : USR1; (sleep 1; kill -USR1 $pid) &
         printf %0100000d 1; } | sleep 3600
bash: printf: write error: Interrupted system call

Isso ocorre porque bashfalha em a) definir seus manipuladores de sinal com SA_RESTART(exceto o SIGCHLDmanipulador) ou b) manipular o EINTRquando chamando write()nos printfe echointernos.

EINTR("Chamada interrompida do sistema") não é uma maneira de indicar uma condição de erro, mas um hack que permite ao programador combinar o bloqueio de leituras / gravações / etc com a manipulação de sinais no loop principal. Nunca deve vazar para o usuário.

Esse bug não aparece com muita frequência porque é uma tarefa fácil obter as condições corretas: write()deve ser feito por um builtin (não por um comando externo), deve preencher o buffer do pipe (o leitor no outro end deve ser muito mais lento ou não ler do pipe, mas ainda estar vivo ), e o script deve usar traps ou a janela do terminal deve ser redimensionada.

E por causa de diversos artefatos de implementação, isso afeta apenas write()s interrompidos , não read()s ou open()s (como por exemplo, o bloqueio open()de um pipe nomeado / fifo).

[1] uma forma disso já foi relatada há algum tempo.

mosvy
fonte