Section 8.1: 后台任务处理

创建后台任务

要创建后台任务,只需在命令后添加一个 &:

$ sleep 10 &
[1] 20024

您还可以按 Ctrl + z 键,将正在运行的进程设为后台作业:

$ sleep 10
^Z
[1]+ Stopped sleep 10

进程的后台和前台

要将后台进程调到前台,可使用 fg 命令和 % 一起执行

$ sleep 10 &
[1] 20024

$ fg %1
sleep 10

现在你可以与进程互动了。要让进程回到后台,可以使用 bg 命令。由于终端会话被占用,你需要先按 Ctrl + z 键停止进程。

$ sleep 10
^Z
[1]+ Stopped sleep 10

$ bg %1
[1]+ sleep 10 &

你也可以偷懒,如果只有一个进程或处理列表中的第一个进程,直接使用单个 % 就可以了。例如

$ sleep 10 &
[1] 20024

$ fg % # to bring a process to foreground 'fg %' is also working.
sleep 10

或者只是

$ % # laziness knows no boundaries, '%' is also working.
sleep 10

此外,只需键入 fg 或 bg,而无需任何参数,即可处理最后一个后台进程:

$ sleep 20 &
$ sleep 10 &
$ fg
sleep 10
^C
$ fg
sleep 20

杀死正在运行的后台任务

$ sleep 10 &
[1] 20024

$ kill %1
[1]+ Terminated sleep 10

睡眠进程在后台运行,进程 id (pid) 为 20024,任务编号为 1。要引用进程,可以使用 pid 或任务编号。如果使用任务编号,则必须在其前缀加上 %。kill 发送的默认 kill 信号是 SIGTERM,它允许目标进程优雅地退出。

一些常见的 kill 信号如下所示。要查看完整列表,请运行 kill -l。

Signal name Signal value Effect
SIGHUP 1 Hangup
SIGINT 2 Interrupt from keyboard
SIGKILL 9 Kill signal
SIGTERM 15 Termination signal

启动或杀死特定进程

杀死一个正在运行的进程最简单的方法可能就是通过进程名来选择它,如下面使用 pkill 命令的示例所示

pkill -f test.py

(或)使用 pgrep 搜索实际进程标识的更可靠的方法

kill $(pgrep -f 'python test.py')

通过 ps -ef | grep name_of_process 使用 grep 命令,然后杀死与结果 pid(进程 ID)相关的进程,也可以得到同样的结果。在测试环境中使用进程名选择进程很方便,但在生产环境中使用脚本时就很危险了:几乎不可能确保进程名与实际要杀死的进程相匹配。在这种情况下,以下方法实际上要安全得多。

用下面的方法启动最终要杀死的脚本。假设要执行并最终杀死的命令是 python test.py。

#!/bin/bash

if [[ ! -e /tmp/test.py.pid ]]; then # Check if the file already exists
    python test.py & #+and if so do not run another process.
    echo $! > /tmp/test.py.pid
else
    echo -n "ERROR: The process is already running with pid "
    cat /tmp/test.py.pid
    echo
fi

这将在 /tmp 目录中创建一个文件,其中包含 python test.py 进程的 pid。如果该文件已经存在,我们将假定命令已在运行,脚本将返回错误信息。

然后,当你想杀死它时,使用下面的脚本:

\#!/bin/bash

if [[ -e /tmp/test.py.pid ]]; then # If the file do not exists, then the
    kill `cat /tmp/test.py.pid` #+the process is not running. Useless
    rm /tmp/test.py.pid #+trying to kill it.
else
        echo "test.py is not running"
fi

这个将准确杀死与命令相关的进程,而不依赖任何不稳定的信息(如运行命令时使用的字符串)。即使在这种情况下,如果文件不存在,脚本也会假定你想杀死一个未运行的进程。

最后一个示例可以很容易地进行改进,以便多次运行同一命令(例如追加到 pid 文件而不是覆盖它),并管理进程在被杀死前死亡的情况。

Section 8.2: 检查在特定端口上运行的进程

查看在 8080 端口运行的进程

lsof -i :8080

Section 8.3: 后台任务继续运行

$ gzip extremelylargefile.txt &
$ bg
$ disown %1

This allows a long running process to continue once your shell (terminal, ssh, etc) is closed.

这样,就算是关闭 shell(终端、ssh 等),后台任务也能继续运行。

Section 8.4: 列出当前工作

$ tail -f /var/log/syslog > log.txt
[1]+ Stopped tail -f /var/log/syslog > log.txt

$ sleep 10 &

$ jobs
[1]+ Stopped tail -f /var/log/syslog > log.txt
[2]- Running sleep 10 &

Section 8.5: 查找运行中进程的信息

ps aux | grep <search-term> shows processes matching search-term

例如:

root@server7:~# ps aux | grep nginx
root 315 0.0 0.3 144392 1020 ? Ss May28 0:00 nginx: master process /usr/sbin/nginx
www-data 5647 0.0 1.1 145124 3048 ? S Jul18 2:53 nginx: worker process
www-data 5648 0.0 0.1 144392 376 ? S Jul18 0:00 nginx: cache manager process
root 13134 0.0 0.3 4960 920 pts/0 S+ 14:33 0:00 grep --color=auto nginx
root@server7:~#

这里,第二列是进程 ID。例如,如果要杀死 nginx 进程,可以使用 kill 5647 命令。建议使用 SIGTERM 而不是 SIGKILL 命令来杀死进程。

Section 8.6: 列出所有进程

有两种常见的方法可以列出系统中的所有进程。这两种方法都能列出所有用户运行的所有进程,但它们的输出格式不同(不同的原因是历史原因)。

ps -ef # lists all processes
ps aux # lists all processes in alternative format (BSD)

可用于检查指定应用程序是否正在运行。例如,检查 SSH 服务器 (sshd) 是否正在运行:

ps -ef | grep sshd