Linux探索之旅 | 第三部分第四课:后台运行及合并多个终端
《Linux探索之旅》全系列
内容简介
- 第三部分第四课:后台运行及合并多个终端
- 第三部分第五课预告:延时执行,唯慢不破
后台运行及合并多个终端
上一课 Linux探索之旅 | 第三部分第三课:监视系统活动,滴水不漏 中,我们简单介绍了进程,也学习了如何列出系统中的进程,如何过滤列表结果,还有如何结束进程。
这一课我们继续乘胜追击,一路向北,来学习进程的后台运行。
我们使用的终端让我们难免有一种感觉:我们每次只能在一个终端中运行一个进程。但其实这是大错特错的。
终端还可以运行后台进程。要使一个进程在后台运行,有几种方法,我们都将学习。
这一课的第三节还将学习screen这个程序,用于同时开多个终端窗口。
&符号和nohup命令:后台运行进程
我们到目前为止用终端做的事情都是眼目所能及的,也就是说:我们运行的命令都是在前台可见的。
这样有一个好处是我们可以看到命令运行的过程,有什么问题可以及时发现。但是也有缺陷,例如有的命令运行耗时良久,我们又不想无所事事,怎么办呢?难道我开一个终端专门执行一个耗时命令,然后为了能做其他事情,我再启动一个终端,那也很不方便。而且,这样的规避方法在非图形界面的终端(还记得我们的tty1~tty6吗?)中是难以实现的,因为只有一个终端窗口。
所以这课显得尤为重要。
事实上,我们可以在同一个终端中同时运行好几个命令。怎么做呢?就需要用到后台进程的概念。
前台进程和后台进程
默认情况下,用户创建的进程都是前台进程。前台进程从键盘读取数据,并把处理结果输出到显示器。
我们可以看到前台进程的运行过程。例如,使用 ls 命令来遍历当前目录下的文件。
ls
这个程序就运行在前台,它会直接把结果输出到显示器。如果 ls 命令需要数据(实际上不需要),那么它会等待用户从键盘输入。
当程序运行在前台时,由于命令提示符($)还未出现,用户不能输入其他命令;即使程序需要运行很长时间,也必须等待程序运行结束才能输入其他命令。
后台进程与键盘没有必然的关系。当然,后台进程也可能会等待键盘输入。
后台进程的优点是不必等待程序运行结束就可以输入其他命令。
那么怎么使一个进程(程序的实例)运行在后台呢?
&符号:在后台运行进程
前面说过,让一个进程在后台运行有几种方法。
我们带大家来学习第一种,很简单:就是在你要运行的命令最后加上&这个符号。
我们可以用熟悉的cp命令做例子。例如,我运行cp命令来拷贝文件:emacs的软件包。
cp emacs-24.4.tar.gz emacs-24.4-copy.tar.gz &
上图中,因为命令最后加了&符号,运行时此进程就成为了后台进程。终端输出了一些信息:
[1] 16525
[1]:这是此终端的后台进程的标号。因为这是第一个后台进程,所以标号为1。
16525:这是进程号(PID),如果你想要结束这个后台进程,你可以用我们上一课学习的kill命令:
kill 16525
我们虽然看不到这个拷贝进程的“所作所为”,但它确实在后台默默进行着文件的拷贝。
如果我们用其他命令试一下,例如find命令,你会吃惊的。
例如我们运行:
find / -name "*log" &
意思是:在根目录/下查找所有以log结尾的文件名的文件,并且在后台运行此进程。
但是你会发现,find命令虽然在后台运行了,但是终端还是会不断显示所有找到的内容或错误信息。虽然我们还可以在终端中输入其他命令,但是一直会跳出find搜索的结果还是很让人感到厌烦的。最后小编不得不把它停止(用kill命令)。
幸好,我们之前学过重定向,我们可以把find的输出结果重定向到文件里,就不会再来烦我们了。
find / -name "*log" > output_find &
这样就不会一直有信息输出了。
当然了,我们还可以更保险一些,将标准错误输出也重定向到同一个文件,这样就不会有任何输出了。
find / -name "*log" > output_find 2>&1 &
但现在有一个问题:虽然我们的进程是被放到后台了,在终端貌似看不到它的运行过程了。但是此进程还是与此终端相关联的,假如我们把终端关闭,那么这个进程也就会结束。
nohup命令:使进程与终端分离
&符号虽然常用,但却有一个不可忽视的缺点:后台进程与终端相关联,一旦终端关闭或者用户登出,进程就自动结束。
如果我们想让进程在以上情况下仍然继续在后台运行,那么我们须要用到nohup命令。
当用户注销(logout)或者网络断开时,终端会收到 HUP(是hangup的缩写,英语《挂断》的意思)信号从而关闭其所有子进程;终端被关闭时也会关闭其子进程。
我们可以用nohup命令使命令不受HUP信号影响。
我们用man来看一下nohup命令的解释:
可以看到,nohup命令的简单描述如下:
run a command immune to hangups, with output to a not-tty
翻译出来大致就是:使得运行的命令不受hangup信号影响,而且输出会存放到一个非tty中。
nohup命令的用法很简单:在nohup命令之后接要运行的命令。例如:
可以看到这次的输出信息是:ignoring input and appending output to nohup.out
大致意思是:忽略输入,把输出追加到nohup.out文件中。
使用nohup命令后,输出会被默认地追加写入到一个叫nohup.out的文件里。
现在,我们的进程已经不受终端关闭或者用户断开连接的影响了,会一直运行。当然了,用kill命令还是可以结束此进程的。
nohup命令相当有用。想象以下场景:
我登录远程服务器,然后运行了一个耗时命令,或者一个需要一直运行的命令,例如一个游戏的服务器程序。这时假如我掉线了,或者我不小心用exit命令退出了登录。那么这个耗时命令也会中止运行。那就很麻烦了。而且,如果这个程序本应该一直运行很久的,我也不可能一直保持登录状态等它结束啊。
我家里还有老婆孩子呢,不能不去做饭啊,我要下班。。。开个小玩笑。
幸好,nohup命令解决了这样的难题。
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的后台进程。
我们输入bg,然后回车。看到如下输出:
上图中,终端首先显示了:
[1]+ top &
表示top命令被转到了后台,但是接着,它又显示了这一条信息:
[1]+ Stopped top
咦,为什么top进程还是暂停着呢?anz理说bg命令会把在后台暂停的进程重新唤醒,使之在后台重新运行啊。
我们用ps命令来查看一下进程信息:
ps -aux
在上图中可以看到,top这个进程的进程号是23051,状态是T。
首先补充一些知识:
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
因此,我们的top进程的状态还是T,也就是停止(stopped)的状态。很奇怪是吗?
我们用其他的命令来测试看看。我们测试find命令。首先运行:
find / -name "*log" > find_log 2>&1
上面这个命令的作用是:在根目录 / 下查找以log结尾的文件,将标准输出和标准错误输出都重定向到find_log文件中。
因此,虽然上述命令在运行,但终端中看不到任何信息。
我们用Ctrl + Z来暂停此进程,并将其转到后台。然后再运行bg命令,使其重新在后台运行。
奇怪了,为什么bg作用于暂停的find命令后,并没有像刚才top命令一样仍然显示Stopped呢?
我们再用ps -aux 看一下:
可以看到,top命令的状态是T,也就是停止(Stopped)。而find命令的状态则是D,也即是不可中断的睡眠(但其实是在运行,等会我们就会看到)。
疑问:所以小编也不清楚为什么对普通的命令(例如find),bg命令是起作用的,会将其转成后台运行。
但是对于top命令,bg为什么不能将其转成后台运行,可能是因为top命令本身比较特殊吧。
也许是因为top命令是前台交互式命令,因此不能被置于后台运行。
小结一下:
如果你本想要使一个命令运行在后台,成为后台进程,但是忘记加&符号了。那么可以按下面的顺序使此进程转为后台运行:
Ctrl + Z:使进程转为后台暂停。
bg:使进程转为后台运行。
那你也许要问:为什么不直接用bg命令一步到位呢?
因为,如果不先用Ctrl + Z将此进程暂停,此进程就一直在前台运行,你没法在命令提示符后面输入啊。
jobs命令:显示后台进程状态
这个命令很强大,毕竟和乔布斯乔老爷子(乔布斯的英文就是jobs,全名是Steve Jobs。job是英语《工作》的意思,jobs就是job的复数形式)一样名字么。
jobs命令的作用是显示当前终端里的后台进程状态。虽然我们可以用ps命令来查看进程状态,但是ps命令输出的进程列表太长了。
聪明如你一定想到了,我们可以用jobs命令来显示刚才那两个进程的状态:top进程和find进程。
jobs命令的输出共分三列,我们逐列来说明:
显示后台进程标号:比如上例中top进程的标号是1,find进程的标号是2,如果还有其他后台进程,那么就会有[3],[4],等等。这个标号和PID(进程号)是不一样的。这个标号只是显示当前终端下的后台进程的一个编号。
显示后台进程状态:比如Stopped是停止的意思,Running是运行的意思。还有其他状态。
命令本身。
可以看到,我们的top进程确实是在后台暂停了,因为显示Stopped,是英语《停止的》的意思。find进程在后台运行,因为显示Running,是英语《运行中》的意思。
fg命令:使进程转到前台
fg是英语foreground的意思,表示《前台》。
与bg命令相反,fg命令的作用是:使进程转为前台运行。
用法也很简单,和bg一样,如果不加参数,那么fg命令作用于最近的一个后台进程。如果加参数,如%2,那么表示作用于本终端中第二个后台进程。
好了,讲了这么多知识点,是不是有点晕呢?没关系。
我们用下面这个状态图来做个总结,应该就很清楚了:
解释一下上图:
如果我们运行一个程序,默认情况下,它会成为一个前台运行的进程。我们可以按组合键Ctrl + C来销毁此进程。
我们也可以使此进程在后台运行。假如运行程序时就用&放在命令最后,那么进程就会在后台运行。
假如在进程运行起来后,按Ctrl + Z,则进程会转到后台,并且停止。此时如果运行bg命令,则进程重新运行,并继续在后台。
fg命令可以使进程转到前台,并且运行。
花点时间好好理解一下这个状态图。这个图很重要,几乎概括了后台前台进程切换的所有情况。
screen命令:合并多个终端
最后一节,我们来学习一个特殊的命令:screen
screen是英语“屏幕”的意思。
screen这个程序(所有命令其实都是程序)通常没有在Linux发行版里预装,如果你的Ubuntu系统里没有screen这个程序,那么可以如此安装:
sudo apt-get install screen
安装完之后,你可以输入screen命令,回车,会显示以下内容:
按回车或空格跳过这个介绍页面。
screen命令用于在一个终端中打开多个终端,就好像在一个页面中开多个标签栏一样(使用过浏览器的朋友肯定有这种使用经验),很酷吧。
但是screen打开的多个终端是重叠在一起的,如果你不知道,还以为只是打开了一个终端,但是我们会学习如何在各个打开的终端间切换。
在我们运行了screen命令后,再用回车键跳过那页介绍之后,我们看到终端里好像没发生什么变化,就跟之前我们看到的终端一样诶,那screen到底做了什么呢?
其实,screen为我们开了一个虚拟终端,就是在当前实际的终端里又开了一个终端。
如果你再运行screen,那么它又会新开一个虚拟终端。那么怎么退出每个新开的虚拟终端呢?可以按Ctrl + D或者用exit命令。
每次你按Ctrl + D或运行exit命令,都会关闭当前所在的虚拟终端,直到最后一个虚拟终端被关闭,screen程序退出,回到我们的实际终端里,如下图:
上图显示了[screen is terminating],表示所有screen开的虚拟终端都已关闭,screen退出(terminate是英语《终结,停止》的意思。施瓦辛格的电影《终结者》就是《The Terminator》)。
现在我们已经知道如何退出screen了。
我们重新回去吧,再输入screen就好了。
在screen程序中,几乎所有的操作都是以Ctrl + a开始的。
以下所有的讲解中,英文字母区分大小写。也就是说:b和B是不同的,前者就是按下键盘上的b键,B则是需要用Shift + b。
如何操作呢?首先,按下Ctrl + a键,然后松开Ctrl键和a键,再按其他键来完成一定的操作。
Ctrl + a再加?号:显示帮助页面
我们先用Ctrl + a键(也就是同时按下Ctrl键和a键),然后松开这两个键,再按下?号(需要Shift + /号)。
screen的帮助页面就会显示:
可以看到,帮助页面显示了各种操作的实现方法。(好好学英语,很有好处吧,可以参看 对于程序员, 为什么英语比数学更重要? 如何学习)
帮助页总共有3页,可以通过第一页第一行[Screen key bingings,page 1 of 3]知道。目前是在3页中的第一页,按空格可以翻到下一页,按回车退出帮助页。
那怎么来阅读这个帮助页面呢?
比如说,你想要知道screen的版本号,那就是version,可以看到需要用到v键。但是光是按v键还不够,因为我们看到第一页第二行Command key: ^A ,就是说以下所有的操作,都需要先按下Ctrl + a键。^表示Ctrl键。
所以说,要知道screen的版本号,可以先按Ctrl + a键(也就是同时按下Ctrl键和a键),然后松开这两个键,再按下v键。就会在左下角显示screen的版本号了。
当然了,这个帮助页面还是不太容易懂,不过我们也不需要全部记住,只要会用常用的一些组合键就好了。
常用的组合按键
Ctrl + a,松开,再按c:创建一个新的虚拟终端。
Ctrl + a,松开,再按w:显示当前虚拟终端的列表。会显示在左下角,类似下图:
此处的 0$ bash 1-$ bash 2*$ bash 表示此时打开了3个虚拟终端,都叫作bash,编号是0,1,2。
有*(星号)的那个虚拟终端就是我们目前所在的虚拟终端,也就是第3个,编号是2。
Ctrl + a,松开,再按A:重命名当前虚拟终端。修改后的名字,你之后再用Ctrl + a,松开,再按w时就会看到。
Ctrl + a,松开,再按n:跳转到下一个虚拟终端。
Ctrl + a,松开,再按p:跳转到上一个虚拟终端。
Ctrl + a,松开,再按Ctrl + a:跳转到最近刚使用的那个虚拟终端。
Ctrl + a,松开,再按0~9数字键:跳转到第0~9号虚拟终端。
Ctrl + a,松开,再按 "(双引号):会让你选择跳转到哪个虚拟终端。
Ctrl + a,松开,再按k:关闭当前终端。
以上是一些常用的screen组合键,下面我们重点来看两个很有用的组合键,分别用于分割虚拟终端和分离screen。
Ctrl + a,松开,再按S:分割虚拟终端为多个小虚拟终端
注意是大写的S,所以是Shif + s。如果这样操作一次,则当前虚拟终端被分割为上下两部分。如下图所示:
如果再按这样操作,就分割成3部分,4部分...
可以看到我在上面的半部分中运行了ls命令,下面的半部分暂时还没跳转过去操作,因此下半部分连命令行提示符也没有,空空的。
那我们如何跳转到下半部分去操作呢?
Ctrl + a,松开,��按Tab键。
光标就会跳转到下半部分了,但是还是没见有命令行提示符,那是因为还没为下半部分创建虚拟终端呢。
所以我们可以新建一个:Ctrl + a,松开,再按c。或者打开一个现有的虚拟终端。
可以看到,我们用Ctrl + a,松开,再按c之后,下半部分的左下角的--变成了3 bash,说明新建了一个虚拟终端,编号是3,也就是第4个(虚拟终端的编号从0开始)。
我们在这个3 bash的虚拟终端里运行top命令,如下:
那么我们如何关闭新分割出来的虚拟终端呢?只要Ctrl + a,松开,再按X(是大写的X,也就是Shift + x)。
Ctrl + a,松开,再按d:分离screen
如果我们在screen程序中,先按Ctrl + a,松开,再按d,就可以使screen程序与当前实际终端分离了,有点类似nohup命令的作用。
这样我们就可以重回我们自己的实际终端了,而screen并没有退出,还在后台运行。
可以看到 [detached from 6815.pts-0.oscar-laptop]
表示我们的screen与实际终端分离(detach是英语《分离,挣脱》的意思)了。
之后如果你要重回screen中,可以输入
screen -r
就又回到刚才的screen的虚拟终端里了。
我们可以使好几个screen进入分离(detached)状态。
可以看到,我们继刚才分离了编号6815的screen进程之后,现在又分离了一个编号13840的screen进程。
之后再运行screen -r想要回去的时候,因为有两个screen分离进程了,实际终端会询问你要回到哪一个,如下图:
你想要回到哪一个就用:
screen -r 编号
就可以了。例如我要回到6815那个screen,只要这样:
screen -r 6815
如果你在实际终端下,输入:
screen -ls
则会列出当前打开着的screen进程:
怎么样,screen是不是很有趣呢?好好练习,就会比较熟练了。
用过Emacs或Vim编辑器的读者,也许觉得screen有点像Emcas或Vim中的一部分功能。
是有点像。不过,screen怎么能和Emacs及Vim如此强大的编辑器相比呢。
总结
我们可以使程序在后台运行,成为后台进程。这样在当前终端中我们就可以做其他事了,而不必等待此进程运行结束。
为了使一个程序在后台运行,可以在命令的最后加上&这个符号。但是,如果你关闭终端或退出登录,此后台进程还是会结束。为了将后台进程与本终端分离,可以使用nohup命令,使得进程不再受终端关闭或用户登出的影响。
如果你运行了一个前台进程,但是想要将其转为后台运行进程。你可以先用Ctrl + Z组合按键将其转为后台暂停,然后运行bg命令使其在后台重新运行。如果你要将一个后台命令(不管它是后台运行还是后台暂停)重新转为前台运行,只要用fg命令就可以了。
screen是一个程序,你可以用apt-get来安装。screen命令使用户能够在一个终端中打开多个虚拟终端。
第三部分第五课预告
今天的课就到这里,一起加油吧!
下一课我们学习:Linux探索之旅 | 第三部分第五课:延时执行,唯慢不破