10

I want to generate a sorted list with all 8-digit numbers — from 00000000 to 99999999. I typed in the 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

response is

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

Why have I got these three errors and malformed result.txt ?

I use

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

Debian GNU/Linux 9.6 (stretch)

Linux kernel: 4.19.0 #2 SMP Thu Nov 1 15:31:34 EET 2018 x86_64 GNU/Linux

7
  • 2
    I can't help but feeling this way of doing it would not be more efficient than seq -w 0 99999999.
    – Kusalananda
    Dec 9, 2018 at 9:56
  • 1
    Then the question is incomplete/incorrect/badly written or something else. Because the script (when completed with the }) works correctly. @GAD3R
    – user232326
    Dec 9, 2018 at 10:31
  • 1
    Note: I can trigger these errors almost on demand. They often appear when I resize my konsole window. Such resizing is almost sufficient in my case, yet not necessary. Dec 9, 2018 at 10:47
  • I can remove the | tee result.txt, and still get the error. Dec 9, 2018 at 12:37
  • Another note: external executable (/bin/echo in my case) instead of echo builtin makes the function immune (or at least less prone) to this issue. Dec 9, 2018 at 16:32

2 Answers 2

8

The specific write error: Interrupted system call error is generated when the console window size is changed while the script is being executed.

Doing a:

 trap '' SIGWINCH

will avoid it.

Note that a

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

Will be both faster and will avoid the SIGWINCH issue.

1
  • 5
    So what is going on?, why have I not seen this before?, Why is a write error, the correct thing to do? Dec 9, 2018 at 12:39
5

This is actually a bug [1] in bash, and it doesn't happen only on SIGWINCH, but also on any signal for which a trap was set:

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

It happens because bash fails to either a) set its signal handlers with SA_RESTART (except for the SIGCHLD handler), or b) handle the EINTR when calling write() in the printf and echo builtins.

EINTR ("Interrupted system call") is not a way to indicate an error condition, but a hack which allows the programmer to combine blocking reads/writes/etc with the handling of signals in the main loop. It should never be leaked to the user.

This bug doesn't show up too frequently because it's quite a feat to get the right conditions in place: the write() should be done by a builtin (not by an external command), it should fill up the pipe buffer (the reader at the other end should be much slower or not reading from the pipe at all but still alive), and the script should use traps or the terminal window should be resized.

And because of diverse implementation artifacts, this only affects interrupted write()s, not read()s or open()s (as eg. the blocking open() of a named pipe/fifo).

[1] a form of this was already reported some time ago.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .