使用 $! 获取 shell 脚本的 PID没有给出正确的(最终)PID

使用 $! 获取 shell 脚本的 PID没有给出正确的(最终)PID

我正在尝试获取 shell 脚本的 PID,以便稍后可以杀死它。

bash "home/lewis/builds/arduino/arduino-1.8.12/arduino" & disown
echo "$!"

上面运行并返回 37977

当我跑步时kill 37977我得到

bash: kill: (37977) - No such process

我认为这是因为脚本/home/lewis/builds/arduino/arduino-1.8.12/arduino随后生成了 37977 以外的其他进程。

有什么方法可以让我获取 shell 脚本或我运行的任何其他命令的最终 PID,通常它很有效,但这个实例给我带来了一个问题。

我需要一个可以转移到其他命令的解决方案,以防这种情况再次发生。

答案1

如果生成的进程正在启动其他进程然后退出,则新进程都应具有相同的进程组 ID (PGID),并且该 ID 应该是原始进程的 PID(在示例中为 37977)。所以你想要的是一种杀死 PGID 中所有进程的方法。这可以通过负 PID 来完成kill,如下所述man kill

          -n     where n is larger than 1.  All processes in process group
                 n are signaled.  When an argument of  the  form  '-n'  is
                 given,  and it is meant to denote a process group, either
                 a signal must be specified first, or the argument must be
                 preceded  by a '--' option, otherwise it will be taken as
                 the signal to send.

所以,你所追求的是:

bash "home/lewis/builds/arduino/arduino-1.8.12/arduino" & disown
kill -TERM -"$!"

如果您需要收集各个 PID 列表,您可以执行以下操作:

bash "home/lewis/builds/arduino/arduino-1.8.12/arduino" & disown
ps -eo pgid,pid | awk -v pid=$! '$1==pid{print $2}')

这将返回 PGID 为 的 PID 列表$!。如果你的 shell 支持数组(bash 支持),你甚至可以这样做:

pids=($(ps -eo pgid,pid | awk -v pid=$! '$1==pid{print $2}'))
for pid in "${pids[@]}"; do echo "Killing $pid"; kill $pid; done

或者您需要的其他任何东西。

相关内容