sqw*_*eek 7 linux bash shell process
我使用 shell 脚本对系统事件做出反应并更新窗口管理器中的状态显示。例如,一个脚本通过侦听多个来源来确定当前的 wifi 状态:
为了实现多路复用,我最终生成了后台进程:
{ wpa_cli -p /var/run/wpa_supplicant -i wlan0 -a echo &
ip monitor address &
while sleep 30; do echo; done } |
while read line; do update_wifi_status; done &
Run Code Online (Sandbox Code Playgroud)
即,设置是每当任何事件源输出一行时,我的 wifi 状态都会更新。整个管道在后台运行(最后一个“&”),因为我还观察了另一个导致脚本终止的事件源:
wait_for_termination
kill $!
Run Code Online (Sandbox Code Playgroud)
kill 应该清理后台进程,但在这种形式中它并不能完全完成这项工作。'wpa_cli' 和 'ip' 进程总是存活,至少,它们也不会在下一个事件中死亡(理论上它们应该得到一个 SIGPIPE;我猜读取进程也必须仍然存在)。
问题是,如何可靠地[并且优雅地!]清理所有产生的后台进程?
sqw*_*eek 10
超级简单的解决方案是在脚本末尾添加:
kill -- -$$
解释:
$$
给了我们正在运行的 shell 的 PID。所以,kill $$
会向 shell 进程发送一个 SIGTERM。但是,如果我们否定PID ,则会kill
向进程组中的每个进程发送一个 SIGTERM 。我们需要--
事先kill
知道这-$$
是一个进程组 ID 而不是一个标志。
请注意,这依赖于正在运行的 shell 作为进程组的领导者!否则,$$
(PID)将与进程组 ID 不匹配,并且您最终会向谁知道在哪里发送信号(好吧,可能没有任何地方,因为如果我们不是一个组,则不太可能有一个具有匹配 ID 的进程组领导者)。
当 shell 启动时,它会创建一个新的进程组 [1]。每个分叉的进程都成为该进程组的成员,除非它们通过系统调用 ( setpgid
)显式更改其进程组。
保证特定脚本作为进程组领导运行的最简单方法是使用setsid
. 例如,我有一些从父脚本启动的状态脚本:
#!/bin/sh
wifi_status &
bat_status &
Run Code Online (Sandbox Code Playgroud)
像这样写,wifi和battery脚本都和父脚本在同一个进程组运行,kill -- -$$
不工作。修复方法是:
#!/bin/sh
setsid wifi_status &
setsid bat_status &
Run Code Online (Sandbox Code Playgroud)
我发现pstree -p -g
可视化进程和进程组 ID 很有用。
感谢所有贡献并让我深入挖掘的人,我学到了东西!:)
[1] shell 是否还有其他情况会创建进程组?例如。启动子shell?我不知道...
归档时间: |
|
查看次数: |
9703 次 |
最近记录: |