在while循环中使用sleep会得到它自己的pid

5
我有一个bash脚本,在循环中进行一些并行处理。我不希望并行处理使CPU负载过高,因此我使用了sleep命令。以下是简化版本。
(while true;do sleep 99999;done)&
因此,我在bash提示符下执行上面的命令,会得到类似以下内容:
[1] 12345
其中[1]是作业编号,12345是while循环的进程ID(pid)。我执行kill 12345,然后得到以下结果:
[1]+ Terminated ( while true; do sleep 99999; done )
看起来整个脚本都被终止了。但是,我执行ps aux|grep sleep,发现sleep命令仍在继续运行,但具有自己的pid!我可以杀死sleep,一切似乎都很好。但是,如果我首先杀死sleep,则while循环将启动新的sleep pid。这让我感到惊讶,因为sleep与while循环不是并行的。循环本身是单个执行路径。
因此,我有两个问题:
1.为什么sleep命令会获得自己的进程ID?
2.如何轻松地杀死while循环和sleep?
6个回答

5
  1. Sleep 会被赋予一个独立的 PID,因为它是一个正在运行但只是等待的进程。使用 which sleep 命令可以查看它的位置。
  2. 你可以使用 ps -uf 命令来查看系统上的进程树。从那里你可以确定 shell 的 PPID(父进程 ID)以及 sleep 进程的父进程 ID。

1
我明白了。我之前以为sleep是bash的内置命令,而不是一个进程。现在更有意义了。 - User1
如果你正在使用bash,type sleeptype -a sleepwhich更好。which是一个外部命令;它无法检测别名、函数或内置命令。比较一下which echotype echo的输出。 - Keith Thompson
@User1:像echo这样的东西是内置命令,因为这使它们更有效率(在某些情况下,例如cd,因为它们具有无法通过运行外部命令实现的语义)。sleep的效率并不重要,所以将其作为内置命令没有太多意义。 - Keith Thompson

2
  1. Because "sleep" is a process, not a build-in function or similar

  2. You could do the following:

    (while true;do sleep 99999;done)&
    whilepid=$!
    kill -- -$whilepid
    
上述代码杀死进程组,因为PID指定为负数(例如-123而不是123)。此外,它使用变量$!,该变量存储最近执行进程的PID。
注意: 当您在交互模式下(即使用命令行提示符)在后台执行任何进程时,它会创建一个新的进程组,这就是您正在发生的情况。这样,相对容易“kill 'em all”,因为您只需要杀死整个进程组。但是,在脚本中执行相同操作时,不会创建任何新组,因为所有新进程都属于脚本PID,即使它们在后台执行(作业控制默认禁用)。要在脚本中启用作业控制,只需在脚本开头添加以下内容:
#!/bin/bash

set -m

1
"

ps --ppid

" 选择所有具有指定父进程pid的进程,例如:
$ (while true;do sleep 99999;done)&
[1] 12345

$ ppid=12345 ; kill -9 $ppid $(ps --ppid $ppid -o pid --no-heading)

1

你可以杀掉进程组。

要查找你的进程组,请运行:

ps --no-headers -o "%r" -p 15864

然后使用以下命令杀死进程组:

kill -- -[PGID]

你可以用一个命令完成所有操作。让我们试一下:

$ (while true;do sleep 99999;done)&
[1] 16151

$ kill -- -$(ps --no-headers -o "%r" -p 16151)
[1]+  Terminated              ( while true; do
    sleep 99999;
done )

1
你尝试过执行 kill %1 吗?这里的 1 是在后台启动命令后得到的数字。
我刚刚在执行 (while true;do sleep 99999;done)& 后尝试了一下,成功终止了它。

0

为了终止while循环和sleep,您可以使用$!,也可以在子shell中使用trap信号处理程序。

(trap 'kill ${!}; exit' TERM; while true; do sleep 99999 & wait ${!}; done)&
kill -TERM ${!}

重新登录后无法执行此操作。 - petertc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接