bash: echo: errore di scrittura: chiamata di sistema interrotta


9

Voglio generare un elenco ordinato con tutti i numeri di 8 cifre - da 00000000 a 99999999. Ho digitato nella 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

la risposta è

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

Perché ho questi tre errori e result.txt non valido?

Io uso

GNU bash, versione 4.4.12 (1) -release (x86_64-pc-linux-gnu)

Debian GNU / Linux 9.6 (tratto)

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


2
Non posso fare a meno di sentire che questo modo di farlo non sarebbe più efficiente di seq -w 0 99999999.
Kusalananda

1
Quindi la domanda è incompleta / errata / scritta male o qualcos'altro. Perché lo script (quando completato con }) funziona correttamente. @ GAD3R
Isaac,

1
Nota: posso innescare questi errori quasi su richiesta. Appaiono spesso quando ridimensiono la mia konsolefinestra. Tale ridimensionamento è quasi sufficiente nel mio caso, ma non necessario.
Kamil Maciorowski il

Posso rimuovere il | tee result.txt, e ancora ottenere l'errore.
ctrl-alt-delor

Un'altra nota: un eseguibile esterno ( /bin/echonel mio caso) invece di echobuiltin rende la funzione immune (o almeno meno soggetta) a questo problema.
Kamil Maciorowski il

Risposte:


6

L' write error: Interrupted system callerrore specifico viene generato quando le dimensioni della finestra della console vengono modificate durante l'esecuzione dello script.

Fare un:

 trap '' SIGWINCH

lo eviterà.

Si noti che a

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

Sarà più veloce ed eviterà il SIGWINCHproblema.


5
Allora, cosa sta succedendo? Perché non l'ho mai visto prima? Perché un errore di scrittura è la cosa corretta da fare?
ctrl-alt-delor

4

Questo è in realtà un bug [1] in bash, e non accade solo SIGWINCH, ma anche su qualsiasi segnale per il quale è stata impostata una trappola:

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

Succede perché bashnon riesce a) impostare i suoi gestori di segnale con SA_RESTART(tranne il SIGCHLDgestore), oppure b) gestire il EINTRquando si chiama write()in printfe echobuiltin.

EINTR("Interruzione della chiamata di sistema") non è un modo per indicare una condizione di errore, ma un hack che consente al programmatore di combinare le letture / scritture / etc di blocco con la gestione dei segnali nel loop principale. Non dovrebbe mai essere trapelato all'utente.

Questo bug non si presenta troppo frequentemente perché è abbastanza un'impresa trovare le giuste condizioni: write()dovrebbe essere fatto da un builtin (non da un comando esterno), dovrebbe riempire il buffer di pipe (il lettore all'altro end dovrebbe essere molto più lento o non leggere affatto dalla pipe ma ancora vivo ) e lo script dovrebbe usare trap o la finestra del terminale dovrebbe essere ridimensionata.

E a causa di diversi artefatti di implementazione, ciò influisce solo su write()s, non read()s o open()s interrotti (come ad esempio il blocco open()di una pipe / fifo denominata).

[1] una forma di questo era già stata segnalata qualche tempo fa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.