我正在尝试计算给定时间段内的所有击键次数。 目前我的代码如下所示:
Killed
返回
$ 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
而不是预期的按键次数。 当我在没有管道的情况下运行超时时输出是预期的
{{1}}
既不更改信号也不添加参数--preserve-status修复此问题。
我想知道为什么这不起作用。 “超时”是否以某种方式劫持xinputs stdout?
修改 但是添加--foreground解决了我的问题。但我不明白为什么。
答案 0 :(得分:0)
它的工作原理是因为这样,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后台命令。
答案 1 :(得分:0)
使用--foreground
时,wc -l
只会看到EOF,因此会打印行数。
如果没有--foreground
,wc -l
会被SIGKILL
杀死。 (我用另一个终端的strace -p $(pidof wc)
跟踪它。)
跟踪timeout
本身,看看它与--foreground
有什么不同:
除了内存地址不同之外:
时间过后,--foreground
只会为分叉的孩子(wait(2)
)杀死clone(2)
,然后退出正常的exit_group(2)
系统调用。
没有--foreground
,它确实
setpgid(0, 0) = 0
分给孩子之前在时间到期后,它kill()
是孩子,然后用kill(0, SIGKILL)
杀死自己。
来自kill(2)
:
如果pid等于0,则sig被发送到调用进程的进程组中的每个进程。
我忘记了信号语义的细节,我不确定为什么这解释了wc
收到SIGKILL
。根据{{1}},pstree
和wc
都是bash的孩子,而不是彼此的孩子。但是,流程按它们在管道中出现的顺序启动。
xinput
手册页说明了timeout(1)
:“在此模式下,COMMAND的子项不会超时”。似乎这包括管道中的后续元素。 IDK如果shell可以安排管道的不同元素不在同一个进程组中以避免这种情况,或者是什么。