Contents

获得NOHUP进程的PID

1. 概述

有时我们在后台运行命令,因为它可能需要很长时间才能完成。通常,如果我们在后台作业运行时注销,它会被终止。但是,我们可以使用nohup 命令运行即使我们注销也会继续运行的作业。 稍后,在注销并再次登录后,我们可能需要获取我们在后台启动的进程的进程标识符 ( PID )。例如,我们可能想检查它是否仍在运行。

在本教程中,我们将了解如何使用nohup获取后台进程的 PID 。我们还将触及shopt 命令的huponexit选项,因为它与nohup相关。

2. 获取使用nohup命令执行的进程的 PID

让我们使用nohup在后台启动一个进程:

$ bash -l
$ nohup sleep infinity >& nohup.out &
[1] 20634
$ exit
logout
$

首先,我们使用bash命令启动了一个交互式登录 shell 。bash的*-l*选项 将 shell 作为登录 shell 启动。

然后,我们使用nohup在后台启动了一个进程sleep infinity。我们将标准输出和标准错误重定向到文件nohup.out

最后,我们使用exit 命令退出了交互式登录 shell 。

2.1. 在启动过程时保存 PID

当我们使用上面的nohup启动进程 时,命令执行的输出是 [1] 20634。括号内的数字1是作业 ID。作业 ID 后面的数字20634是通过执行sleep infinity命令生成的进程的 PID。

我们可以稍后使用这个 PID 来检查或控制过程。例如,我们可以检查进程是否还在运行:

$ ps -ef -o pid | grep 20634
20634

与其手动记下进程的 PID 以记住它,我们可以将 PID 保存到文件中并稍后使用:

$ bash -l
$ nohup sleep infinity >& nohup.out &
[1] 21443
$ echo $! > $HOME/pid.nohup
$ exit
logout
$ cat $HOME/pid.nohup
21443

现在,我们将 PID 存储在文件*$HOME/pid.nohup中。$!* 是在后台运行的最后一个命令的 PID,在我们的例子中是sleep infinity

因此,我们可以稍后使用这个 PID,例如,杀死进程:

$ kill -9 `cat $HOME/pid.nohup`
[1]+  Killed                  nohup sleep infinity

2.2. 使用ps命令

如果我们在使用nohup启动进程时忘记记下进程的 PID ,我们可以稍后使用ps 获取它。让我们在现有进程中搜索命令sleep infinity

$ ps -ef | grep "sleep infinity"
alice     21443       1  0  00:27 pts/0    00:00:00 sleep infinity
alice     21673    4672  0  00:27 pts/0    00:00:00 grep sleep infinity

在这里,我们使用grep过滤了ps的输出。我们没有在搜索中使用术语“ nohup ”,因为它没有出现在ps命令的输出中。

由于管道中的grep “sleep infinity”命令也列在输出中,我们可以使用grep进一步过滤它:

$ ps -ef | grep "sleep infinity" | grep -v grep
alice     21443       1  0  00:27 pts/0    00:00:00 sleep infinity

最后,我们可以使用awk 命令仅打印进程的 PID :

$ ps -ef | grep "sleep infinity" | grep -v grep | awk '{print $2}'
21443

2.3. 使用pgrep命令

或者,如果我们在使用nohup启动进程后忘记记录进程的 PID ,我们也可以使用pgrep命令:

$ pgrep -a sleep
21443 sleep infinity

在这里,pgrep的*-a*选项将命令连同它的 PID 一起打印出来。

3 、 shopt命令的huponexit选项

让我们再次在交互式登录 shell 中在后台生成一个进程并注销。但是,在这种情况下,我们将在没有nohup的情况下启动该过程:

$ bash -l
$ sleep infinity &
[1] 25101
$ exit
logout
$

让我们检查进程是否仍在运行:

$ ps -ef -o pid | grep 25101
25101

即使我们从交互式登录 shell 中注销,该进程似乎仍在运行。那么,这是否意味着如果我们希望后台进程在注销后继续运行,我们就不必使用nohup呢?

答案是,如果我们想要可移植性,我们应该使用nohup。仅在没有nohup的情况下在后台运行命令可能并不总是有效。

**事实上,这个问题与 shell 选项huponexit相关。**我们可以使用shopt命令检查此选项的值:

$ shopt | grep huponexit
huponexit       off

shopt命令用于设置和显示几个 shell 选项。如果huponexit选项off,当交互式登录 shell 退出时,Bash 不会向在该会话中生成的已经运行的进程发送SIGHUP信号。这就是为什么我们通过执行sleep infinity命令生成的进程在使用**exit命令终止登录 shell 后仍然存在的原因。

可以启用和禁用huponexit选项。我们可以使用*-s选项来启用它,使用-u*选项来禁用它:

$ shopt -s huponexit
$ shopt | grep huponexit
huponexit       on
$ shopt -u huponexit
huponexit       off

现在,让我们启用huponexit选项并检查行为:

$ bash -l
$ shopt –s huponexit
$ shopt | grep huponexit
huponexit       on
$ sleep infinity &
[1] 26238
$ exit
logout
$ ps –ef –o pid | grep 26238
$

现在,在我们退出登录 shell 后,该进程不再处于活动状态,因为内核在退出时向该进程发送信号SIGHUP。因此,进程在收到此信号时终止。