nohup与前台后台操作
1. & 符号和 nohup 命令:后台运行进程
我们到目前为止用终端做的事情都是目所能及的,也就是说:我们运行的命令都是在前台可见的。
这样的一个好处是我们可以看到命令运行的过程,有什么问题可以及时发现。但是也有缺陷,例如有的命令运行耗时良久,我们又不想无所事事,怎么办呢?难道我开一个终端专门执行一个耗时命令,然后为了能做其他事情,我再启动一个终端,那也很不方便。
事实上,我们可以在同一个终端中同时运行好几个命令。怎么做呢?就需要用到后台进程的概念。
前台进程和后台进程
默认情况下,用户创建的进程都是前台进程。前台进程从键盘读取数据,并把处理结果输出到显示器。
我们可以看到前台进程的运行过程。例如,使用 ls 命令来遍历当前目录下的文件。
ls
这个程序就运行在前台,它会直接把结果输出到显示器。如果 ls 命令需要数据(实际上不需要),那么它会等待用户从键盘输入。
当程序运行在前台时,由于命令提示符($)还未出现,用户不能输入其他命令;即使程序需要运行很长时间,也必须等待程序运行结束才能输入其他命令。
后台进程与键盘没有必然的关系。当然,后台进程也可能会等待键盘输入。
后台进程的优点是不必等待程序运行结束就可以输入其他命令。
那么怎么使一个进程(程序的实例)运行在后台呢?
& 符号:在后台运行进程
前面说过,让一个进程在后台运行有几种方法。
我们带大家来学习第一种,很简单:就是在你要运行的命令最后加上 & 这个符号。
我们可以用熟悉的 cp 命令做例子。例如,我运行 cp 命令来拷贝文件:emacs 的软件包。当然了,你可以用其他文件来测试。
cp emacs-26.2.tar.gz emacs-26.2-copy.tar.gz &
命令最后加了 & 符号,运行时此进程就成为了后台进程。终端输出了一些信息:
[1] 2051
-
[1] :这是此终端的后台进程的标号。因为这是第一个后台进程,所以标号为 1。
-
2051 :这是进程号(PID),如果你想要结束这个后台进程,你可以用 kill 命令:
kill 2051
我们虽然看不到这个拷贝进程的“所作所为”,但它确实在后台默默进行着文件的拷贝。
可以看到,终端显示了:
[1]+ Done cp emacs-26.2.tar.gz emacs-26.2-copy.tar.gz
Done 是英语“完成的”的意思,表示这个后台进程的任务已经完成了。
nohup 命令:使进程与终端分离
& 符号虽然常用,但却有一个不可忽视的缺点:后台进程与终端相关联。一旦终端关闭或者用户登出,进程就自动结束。
如果我们想让进程在以上情况下仍然继续在后台运行,那么我们须要用到 nohup 命令。
当用户注销(logout)或者网络断开时,终端会收到 HUP(是 hangup 的缩写,英语“挂断”的意思)信号从而关闭其所有子进程;终端被关闭时也会关闭其子进程。
我们可以用 nohup 命令使命令不受 HUP 信号影响。
我们用 man 来看一下 nohup 命令的解释:
nohup 命令的简单描述如下:
run a command immune to hangups, with output to a non-tty
翻译出来大致就是:“使得运行的命令不受 hangup 信号影响,而且输出会存放到一个非 tty 中”。
nohup 命令的用法很简单:在 nohup 命令之后接要运行的命令。例如,我们可以用 nohup 配合 cp 命令来实现文件的拷贝(这次拷贝的是 node.js 的源码。当然了,你可以用其他文件来测试):
nohup cp node-v10.15.3.tar.gz node-v10.15.3-copy.tar.gz
可以看到这次的输出信息是:“ignoring input and appending output to nohup.out”。
大致意思是:“忽略输入,把输出追加到 nohup.out 文件中”。
使用 nohup 命令后,输出会被默认地追加写入到一个叫 nohup.out 的文件里。
现在,我们的进程已经不受终端关闭或者用户断开连接的影响了,会一直运行。当然了,用 kill 命令还是可以结束此进程的。要获知进程号,可以用我们之前学过的 ps 命令配合 grep 来查找。
ps -ax | grep command
上面命令里的 command 指代 nohup 后面跟着的命令。
nohup 命令相当有用。想象以下场景:
我登录远程服务器,然后运行了一个耗时命令,或者一个需要一直运行的命令,例如一个游戏的服务器程序。这时假如我掉线了,或者我不小心用 exit 命令退出了登录。那么这个耗时命令也会中止运行。那就很麻烦了。而且,如果这个程序本应该一直运行很久的,我也不可能一直保持登录状态等它结束啊。
我家里还有老婆孩子呢,不能不去做饭啊,我要下班… 开个小玩笑。
幸好,nohup 命令解决了这样的难题。
一般我们也会把 nohup 和 & 一起使用,例如:
nohup cp node-v10.15.3.tar.gz node-v10.15.3-copy.tar.gz &
2. Ctrl + Z,jobs,bg 和 fg 命令:控制进程的前后台切换
我们来考虑一种情况:假如你要将进程转到后台运行,但是执行命令时忘记了在最后加上 & 符号。
如何再使此进程转为后台进程呢?有几种方法。我们一一来学习。
Ctrl + Z:转到后台,并暂停运行
我们用 top 命令来演示。运行:
top
因为 top 命令的作用是实时地显示各种系统信息和进程列表。这时,我们按下 Ctrl + Z 这个组合键
可以看到终端显示了:
[1]+ Stopped top
这行信息。
stopped 是英语“停止的”的意思,我们又看到 [1] 这个熟悉的信息,表示这是此终端第一个后台进程。
所以表示 top 命令被放到了后台,此进程还是驻留在内存中,但是被暂停运行了。这个时候命令提示符又出现了,我们可以做其他事情了。
bg 命令:使进程转到后台
经过上面的 Ctrl + Z 操作,我们可怜的 top 进程已经被“打入冷宫”(转入后台,并且被暂停运行了)。
但是皇后不甘心啊:“臣妾虽然做不到,但即使在冷宫中,我也要工于心计、运筹帷幄,以期早日打败甄嬛。”
那怎么办呢?可以运行 bg 命令。
就是很简单地输入 bg,然后回车。bg 是英语 background 的缩写,表示“后台”。
bg 命令的作用是将命令转入后台运行。假如命令已经在后台,并且暂停着,那么 bg 命令会将其状态改为运行。
不加任何参数,bg 命令会默认作用于最近的一个后台进程,也就是刚才被 Ctrl + Z 暂停的 top 进程。如果后面加 %1,%2 这样的参数(不带 %,直接 1,2 这样也可以),则是作用于指定标号的进程。因为进程转入后台之后,会显示它在当前终端下的后台进程编号。例如目前 top 进程转入了后台,它的进程编号是 1(可以由 [1]+ 推断)。依次类推,bg %2 就是作用于编号为 2 的后台进程。
补充一些知识:
Linux 中,进程有 5 种状态:
- 运行 (正在运行或在运行队列中等待)
- 中断 (休眠中, 受阻, 在等待某个条件的形成或接受到信号)
- 不可中断 (收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)
- 僵死 (进程已终止, 但进程描述符存在, 直到父进程使用 wait4() 系统调用后释放)
- 停止 (进程收到 SIGSTOP, SIGSTP, SIGTIN, SIGTOU 信号后停止运行)
ps 命令标识进程的 5 种状态码如下:
- D 不可中断 uninterruptible sleep (usually IO)
- R 运行 runnable (on run queue)
- S 中断 sleeping
- T 停止 traced or stopped
- Z 僵死 a defunct (“zombie”) process
jobs 命令:显示后台进程状态
这个命令很强大,毕竟和乔布斯乔老爷子(乔布斯的英文就是 jobs,全名是 Steve Jobs。job 是英语“工作”的意思,jobs 是复数形式)一样名字么。
jobs 命令的作用是显示当前终端里的后台进程状态。虽然我们可以用 ps 命令来查看进程状态,但是 ps 命令输出的进程列表太长了。
jobs 命令的输出共分三列,我们逐列来说明:
- 显示后台进程标号:比如上例中 top 进程的标号是 1,grep 进程的标号是 2,如果还有其他后台进程,那么就会有 [3],[4]等等。这个标号和 PID(进程号)是不一样的。这个标号只是显示当前终端下的后台进程的一个编号;
- 显示后台进程状态:比如 Stopped 是“停止的”的意思,Running 是“运行的”的意思。还有其他状态;
- 命令本身。
fg 命令:使进程转到前台
fg 是英语 foreground 的意思,表示“前台”。
与 bg 命令相反,fg 命令的作用是:使进程转为前台运行。
用法也很简单,和 bg 一样,如果不加参数,那么 fg 命令作用于最近的一个后台进程;如果加参数,如 %2,那么表示作用于本终端中第二个后台进程。
解释一下上图:
- 如果我们运行一个程序,默认情况下,它会成为一个前台运行的进程。我们可以按组合键 Ctrl + C 来销毁此进程。
- 我们也可以使此进程在后台运行。假如运行程序时就用 & 放在命令最后,那么进程就会在后台运行。
- 假如在进程运行起来后,按 Ctrl + Z,则进程会转到后台,并且停止。此时如果运行 bg 命令,则进程重新运行,并继续在后台。
- fg 命令可以使进程转到前台,并且运行。
花点时间好好理解一下这个状态图。这个图很重要,几乎概括了后台前台进程切换的所有情况。
小结
- 我们可以使程序在后台运行,成为后台进程。这样在当前终端中我们就可以做其他事了,而不必等待此进程运行结束。
- 为了使一个程序在后台运行,可以在命令的最后加上 & 这个符号。但是,如果你关闭终端或退出登录,此后台进程还是会结束。为了将后台进程与本终端分离,可以使用 nohup 命令,使得进程不再受终端关闭或用户登出的影响。
- 如果你运行了一个前台进程,但是想要将其转为后台运行进程。你可以先用 Ctrl + Z 组合键将其转为后台暂停,然后运行 bg 命令使其在后台重新运行。如果你要将一个后台命令(不管它是后台运行还是后台暂停)重新转为前台运行,只要用 fg 命令就可以了。