在后台运行 Linux 命令的方法

本文探讨了一些如何在后台运行 Linux 命令,以及如何在终端关闭之后继续运行命令的方法。

一般来讲,我们在终端运行的命令都会将输出打印到终端,在命令结束之后才可以继续运行下一条。这些命令都是运行在前台的。如果你想在命令运行中间的时候做点别的事,除了重新打开一个终端之外,还有以下几种办法。

在后台运行 Linux 命令

在后台运行命令,只需在命令后加上 &

1
[command] &

例如,sleep 100 & 会让 sleep 100 在后台运行,命令行会返回该命令的进程 ID:

1
2
$ sleep 100 &
[1] 3409

此时输入 jobs,可以看到当前终端正在后台运行的命令,jobs -l 则会显示当前终端在后台运行与已经完成的命令:

1
2
3
4
5
6
$ sleep 100 &
[1] 3410
$ jobs
[1]+ Running sleep 100 &
$ jobs -l
[1]+ 3410 Running sleep 100 &

请注意,这样运行的命令依旧会向终端输出信息,包括标准输入 (stdin),标注输出 (stdout) 与标准错误 (stderr)。如果连这也不想要,可以使用如下命令:

1
[command] > /dev/null 2>&1 & 

/dev/null 2>&1 意味着将 stdout 输出到 /dev/nullstderr 输出到 stdout(所以最终都会转移到 /dev/null)。/dev/null 是一个特殊的文件,它可以忽略所有输入的信息。

将前台的 Linux 命令转至后台

如果在前台已经有运行的命令,可以先用 Ctrl + z 将命令中断,然后输入 bg 将命令转入后台继续运行。

1
2
3
4
5
6
7
sleep 100
^Z
[1]+ Stopped sleep 100
$ bg
[1]+ sleep 100 &
$ jobs -l
[1]+ 3411 Running sleep 100 &

想再将其转为前台运行,输入 fg

1
2
$ fg
sleep 100

如果有多个在后台运行的任务,需要先用 jobs -l 看一下任务编号,再用 fg %[job-id] 把需要的任务转到前台 (bg 的使用同理):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sleep 100
^Z
[1]+ Stopped sleep 100
$ sleep 100
^Z
[2]+ Stopped sleep 100
$ jobs -l
[1]- 3412 Stopped sleep 100
[2]+ 3413 Stopped sleep 100
$ bg %2
[2]+ sleep 100 &
$ jobs -l
[1]+ 3412 Stopped sleep 100
[2]- 3413 Running sleep 100 &
$ fg %2
sleep 100

如果需要结束进程,可以使用 kill -9 [process-id]

1
2
3
4
5
6
7
sleep 100 &
[1] 3414
$ jobs -l
[1]+ 3414 Running sleep 100 &
$ kill -9 3414
$ jobs -l
[1]+ 3414 Killed sleep 100

让 Linux 命令在退出终端后仍可继续运行

但是,当任务在后台运行时关闭终端,你会发现任务还是停止了。要让命令在终端结束之后还能继续运行,需要进行 disown。运行 disown 之前需要将任务先放入后台。

如果你有多个后台任务,需要先用 jobs -l 查看任务编号,再运行 disown %[job-id]

使用该命令后,该任务会与当前的终端 session 脱离,这也就意味着 jobs -l 里将不会看到该任务,也不能使用 fgbg 这些命令了。如果你想要看到它,可以使用 ps aux 命令,这会列出所有正在运行的进程,无论是否属于该终端。当然,此时关闭终端,该任务不会被挂起,仍会继续运行。

如果你在运行 disown 之前没有让任务恢复运行,那么即使你 disown 了该任务,任务依旧处于 Stopped 状态,如果你运行 ps ax,可以看到该任务的状态是 T。在该状态下,只有该任务收到 SIGCONT 信号才会继续运行。但是对于 disown 之后的任务,无法使用 fg 恢复它(因为它已经不属于你)。此时,你可以使用 kill -sigcont [process-id] 使它恢复运行。需要注意的是,即使你可以让它恢复运行,也不能撤销 disown 的操作,也就是说你无法将该任务带回到你的终端。

当然,你也可以在任务开始之前使用 nohup 命令。这个命令会使任务忽略所有的 SIGHUP 挂起信号。SIGHUP 就是终端在关闭时会向它所控制的进程发送的终止信号。

1
nohup [command] &

命令的输出会被放入 nohup.out 文件:

1
2
3
4
5
$ nohup sleep 100 &
[1] 3416
nohup: ignoring input and appending output to 'nohup.out'
$ jobs -l
[1]+ 3416 Running nohup sleep 100 &

你可以用这样的格式忽略所有输出:

1
nohup [command] > /dev/null 2>&1 &

当然,把 /dev/null 换成别的文件,即可把输出定向至该文件。