![如何在 bash shell 脚本中获取子进程的 PID 到父进程?](https://linux22.com/image/65550/%E5%A6%82%E4%BD%95%E5%9C%A8%20bash%20shell%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E8%8E%B7%E5%8F%96%E5%AD%90%E8%BF%9B%E7%A8%8B%E7%9A%84%20PID%20%E5%88%B0%E7%88%B6%E8%BF%9B%E7%A8%8B%EF%BC%9F.png)
我的shell脚本如下:
#!/bin/bash
./process1 #It will create a sub process: sub_process1
while [ condition ]; do
break
done
kill -9 process1 and sub_process1
在我的脚本中,它将创建一个进程:process1。 process1 将创建一个子进程:sub_process1。
在脚本完成之前,需要杀死process1和sub_process1。
杀死 process1 很容易,因为它会将 PID 写入文件。但 sub_process1 不会。由于 sub_process1 是第三方组件,因此我无法触及源代码。
有一个解决方案可以获取sub_process1的PID:
- 使用命令枚举所有进程
ps aux
; - 使用命令获取每个进程的 PPID(父进程 ID)
ps -f [PID]
。如果PPID等于process1的PID,则该进程一定是sub_process1。
上面的解决方案有点复杂。有没有一个简单的解决方案可以获取子进程ID?
多谢。
答案1
由于您将其标记为 Linux: pgrep
/pkill
来救援:
PID_OF_SUB_PROCESS1=$( pgrep -P $PID_OF_PROCESS1 )
pkill -P $PID_OF_PROCESS1
答案2
process
您可以通过将其作为后台进程运行来获取其进程 ID 。
./process1 &
pid1=$!
wait "$pid1"
该wait
命令等待process1
退出(但不等待其子进程),就像在原始脚本中一样。请注意,在原始脚本中,process1
最后没有要终止的内容:./process1
命令仅在process1
退出时完成。该进程可能有一个同名的子进程(即该程序可能调用了fork
但不是execve
)。如果您想在脚本process1
启动后立即继续运行该脚本,请省略该wait
行。
如果您有pkill
命令,这是杀死进程的所有子进程的便捷方法。请注意,该进程必须仍在运行,或者必须是僵尸,否则子进程的父进程 ID 将重置为 1,并且您无法再以这种方式跟踪它们。只要您没有wait
在脚本中调用,后台进程 ID 就会保持有效。
./process1 &
pid1=$!
…
pkill -9 -P "$pid1"
kill -9 "$pid1"
递归地跟踪进程、其子进程及其子进程的另一种方法是跟踪进程组。进程的子进程具有相同的进程组,除非它们显式更改它。在 Linux 上,您可以使用setsid
命令在其自己的进程组中运行程序。进程组由原始进程的进程ID来标识。要终止进程组中的所有进程,请将进程组 ID 的负数传递给kill
。
setsid ./process1 &
pgid1=$!
…
kill -9 "-$pgid1"
跟踪进程的另一种方法是让它们打开文件。只要进程不关闭文件,这种方法就有效,因此它可能不适用于打算作为守护进程运行的程序。使用命令fuser
杀死打开该文件的进程。
tmpfile=$(mktemp)
process1 <"$tmpfile"
…
fuser -k -9 "$tmpfile"
答案3
你能做的就是kill -TERM
你进程组。如果您的脚本是从 shell 调用的,它将拥有自己的进程组,该进程组等于脚本的 PID:
kill -TERM -$$
如果以其他方式调用它,它的进程组 ID 可能不等于它的 PID:
kill -TERM -`ps -o pgid $$ | tail -1`
你不应该kill -9
在脚本或程序中,除非你给程序一个公平的机会kill -TERM
。
执行 afind pid and kill it
会受到竞争条件的影响(尽管它们不会经常演示,除非您的盒子疯狂地产生进程)。pid
s 是一个移动目标,除非你要杀死的 pid 是你的孩子,并且你已经确保 pid 不会因为不等待而被回收(据我所知,你在 bash 中很难做到这一点),否则你不能 100% 确定您正在杀死正确的进程(在找到 pid 和杀死之间,该进程可能已经死亡,而另一个进程可能已经获取了 pid)。
答案4
您需要使用setsid ./process1 & pgid=$!
或使用创建单独的进程组作业控制:set -m; ./process1 & pgid=$!; set +m
然后像这样杀死整个进程组:kill -- -$pgid
。更多信息这里