在后台运行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换成别的文件,即可把输出定向至该文件。