如何在 bash shell 脚本中获取子进程的 PID 到父进程?

如何在 bash shell 脚本中获取子进程的 PID 到父进程?

我的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:

  1. 使用命令枚举所有进程ps aux
  2. 使用命令获取每个进程的 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会受到竞争条件的影响(尽管它们不会经常演示,除非您的盒子疯狂地产生进程)。pids 是一个移动目标,除非你要杀死的 pid 是你的孩子,并且你已经确保 pid 不会因为不等待而被回收(据我所知,你在 bash 中很难做到这一点),否则你不能 100% 确定您正在杀死正确的进程(在找到 pid 和杀死之间,该进程可能已经死亡,而另一个进程可能已经获取了 pid)。

答案4

您需要使用setsid ./process1 & pgid=$!或使用创建单独的进程组作业控制set -m; ./process1 & pgid=$!; set +m然后像这样杀死整个进程组:kill -- -$pgid。更多信息这里

相关内容