bash:echo:写入错误:中断的系统调用

bash:echo:写入错误:中断的系统调用

我想生成一个包含所有 8 位数字的排序列表 - 从 00000000 到 99999999。我在 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

响应是

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

为什么我会收到这三个错误和格式错误的 result.txt ?

我用

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

Debian GNU/Linux 9.6(延伸)

Linux 内核:4.19.0 #2 SMP 11 月 1 日星期四 15:31:34 EET 2018 x86_64 GNU/Linux

答案1

write error: Interrupted system call当执行脚本时更改控制台窗口大小时,会生成特定错误。

做一个:

 trap '' SIGWINCH

会避免它。

请注意,一个

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

既会更快,也会避免这个SIGWINCH问题。

答案2

这实际上是一个错误[1]在 中bash,并且它不仅发生在 上SIGWINCH,而且还发生在设置了陷阱的任何信号上:

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

发生这种情况是因为bash未能 a) 设置其信号处理程序SA_RESTART(处理程序除外SIGCHLD),或 b)在调用和内置函数EINTR时处理该信号处理程序。write()printfecho

EINTR(“中断的系统调用”)不是一种指示错误情况的方法,而是一种允许程序员将阻塞读/写等与主循环中的信号处理结合起来的方法。它绝对不应该泄露给用户。

这个错误不会太频繁地出现,因为获得正确的条件是一项相当大的壮举:应该write()内置(不是通过外部命令),它应该填满管道缓冲区(另一端的阅读器应该是很多速度较慢或根本不从管道读取但还活着),并且脚本应使用陷阱或应调整终端窗口的大小。

并且由于不同的实现工件,这仅影响中断的write()s,而不影响read()s 或open()s(例如open()命名管道/fifo 的阻塞)。

[1]这种形式已经存在报道前一段时间。

相关内容