bash: echo: erreur d'écriture: appel système interrompu

9

Je veux générer une liste triée avec tous les nombres à 8 chiffres - de 00000000 à 99999999. J'ai tapé dans le 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 réponse est

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

Pourquoi ai-je ces trois erreurs et result.txt malformé?

j'utilise

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

Debian GNU / Linux 9.6 (stretch)

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

hon
la source
2
Je ne peux pas m'empêcher de ressentir cette façon de faire ne serait pas plus efficace que seq -w 0 99999999.
Kusalananda
1
Ensuite, la question est incomplète / incorrecte / mal écrite ou autre chose. Parce que le script (une fois terminé avec le }) fonctionne correctement. @ GAD3R
Isaac
1
Remarque: je peux déclencher ces erreurs presque à la demande. Ils apparaissent souvent lorsque je redimensionne ma konsolefenêtre. Un tel redimensionnement est presque suffisant dans mon cas, mais pas nécessaire.
Kamil Maciorowski
Je peux supprimer le | tee result.txt, et toujours obtenir l'erreur.
ctrl-alt-delor
Une autre remarque: l'exécutable externe ( /bin/echodans mon cas) au lieu de echola fonction intégrée rend la fonction immunisée (ou du moins moins sujette) à ce problème.
Kamil Maciorowski

Réponses:

6

L' write error: Interrupted system callerreur spécifique est générée lorsque la taille de la fenêtre de la console est modifiée pendant l'exécution du script.

Faire un:

 trap '' SIGWINCH

va l'éviter.

Notez qu'un

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

Sera à la fois plus rapide et évitera le SIGWINCHproblème.

Isaac
la source
5
Alors, que se passe-t-il ?, pourquoi n'ai-je pas vu cela auparavant?, Pourquoi une erreur d'écriture, la bonne chose à faire?
ctrl-alt-delor
4

Il s'agit en fait d'un bug [1] dans bash, et cela ne se produit pas seulement sur SIGWINCH, mais aussi sur n'importe quel signal pour lequel une interruption a été définie:

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

Cela se produit car bashne parvient pas à a) définir ses gestionnaires de signaux avec SA_RESTART(à l'exception du SIGCHLDgestionnaire), ou b) à gérer le EINTRlors de l'appel write()dans les commandes internes printfet echo.

EINTR("Appel système interrompu") n'est pas un moyen d'indiquer une condition d'erreur, mais un hack qui permet au programmeur de combiner le blocage des lectures / écritures / etc avec le traitement des signaux dans la boucle principale. Il ne doit jamais être divulgué à l'utilisateur.

Ce bogue n'apparaît pas trop souvent car c'est tout un exploit de mettre en place les bonnes conditions: le write()devrait être fait par un builtin (pas par une commande externe), il devrait remplir le buffer de pipe (le lecteur à l'autre end doit être beaucoup plus lent ou ne pas lire du tout, mais toujours vivant ), et le script doit utiliser des interruptions ou la fenêtre du terminal doit être redimensionnée.

Et en raison de divers artefacts d'implémentation, cela n'affecte que les write()s interrompus , pas les read()s ou les open()s (comme par exemple le blocage open()d'un canal / fifo nommé).

[1] une forme de cela a déjà été signalée il y a quelque temps.

mosvy
la source