pipe道输出从“超时”到“wc -l”失败

我正在计算给定时间内的所有按键。 目前我的代码如下所示:

$ timeout -s 9 10s xinput test 8 | wc -l 

这返回

 Killed 

而不是预期的按键次数。 当我运行没有pipe道超时输出如预期

 $ timeout -s 9 20s xinput test 8 key release 36 key press 42 key release 42 key press 26 key release 26 key press 28 key release 28 key press 38 key release 38 key press 46 key release 46 key press 31 key release 31 key press 41 key release 41 key press 26 key release 26 Killed 

无论是改变信号还是增加参数 – 保持状态都可以解决这个问题。

我想知道为什么这不起作用。 '超时'劫持xinputs stdout不知何故?

编辑:然而join – foreground解决我的问题。 不过,我不明白为什么。

它的工作原理是这样,timeout命令不会杀死任何子进程,从而避免wc获得线数。

 $ timeout --foreground -s 15 10s xinput test 8 | wc -l 

另一种方式是这样的:

 $ xinput test 8 > output.log & sleep 10 && wc -l output.log && kill $! 

这样,你不需要超时。 第一部分将xinput输出重定向到一个文件,并将命令发送到后台,然后休眠(等待文件接收到一些数据),在睡眠结束后,我们运行wc并优雅地终止xinput后台命令。

--foregroundwc -l只是看到一个EOF,所以它会打印行数。

没有--foregroundwc -lSIGKILL杀死。 (我从另一个终端用strace -p $(pidof wc)跟踪它)。

跟踪timeout本身,看看它有什么不同的/不带--foreground

除了内存地址不同:

在时间到期之后,– --foreground只会杀死并wait(2) s分支的子( clone(2) ),然后以正常的exit_group(2)系统调用退出。

没有 – --foreground ,它确实

 setpgid(0, 0) = 0 

在分娩之前。 在时间到期后,它kill() ,然后杀死自己kill(0, SIGKILL)

kill(2)

如果pid等于0,则将sig发送到调用进程的进程组中的每个进程。

我忘记了信号语义的细节,我不知道为什么这解释wc接收SIGKILL 。 根据pstreewcxinput既是bash的子项,也不是彼此的子项。 虽然进程是按照它们出现在管道中的顺序启动的。


timeout(1)手册页说--foreground :“在这种模式下,COMMAND的孩子不会超时”。 看来这包括管道中的后续元素。 IDK如果shell可能已经安排了管道的不同元素不在同一个进程组中以避免这个,或者是什么。