当你在终端上运行一个命令时,如果该命令很快就执行完成,那么没什么可说的,如果该命令是一个耗时操作,或者我们就是要让他一直运行着,那么可能会出现下面问题:
- 你的终端一直被该命令占据着
- 你的终端充满了很多输出数据或者错误及诊断信息
- 如果终端关闭,则程序或命令就会终止
在Unix/Linux中,运行在后台的进程被称为守护进程daemon,通常在后台运行的进程为非交互式,即该进程不会从用户中读取输入。那么如何运行一个命令或程序,使其在后台运行,而无需担心关闭终端程序就结束,同时我们还可以继续做其他事情呢?
nohup ... &
举一个简单的例子,看看如何使用 & 号将下面这个命令放到后台运行:
# cp -R from/data/dir/ to/backup/dir/
这个命令的目的是将from/data/dir/的内容递归地复制到to/backup/dir/中。看起来很简单,但是如果原目录里面的文件太大,在执行过程中终端就会一直被占据。
所以,可以在命令的末尾加上一个 & 号,将这个任务放到后台去执行:
# cp -R from/data/dir/ to/backup/dir/ & [1] 1280
任务被放到后台执行之后,就可以继续在同一个终端上工作了,甚至关闭终端也不影响这个任务的正常执行。
当使用&将一个进程放置到后台运行的时候,shell会提示这个进程的进程ID。在Linux系统中运行的每一个进程都有一个唯一的进程ID,你可以使用进程ID来暂停、恢复或者终止对应的进程,因此进程 ID 是非常重要的。
jobs命令可以显示当前终端正在运行的进程,包括前台运行和后台运行的进程。它对每个正在执行中的进程任务分配了一个序号(这个序号不是进程ID),可以使用这些序号来引用各个进程任务。
# jobs [1]- Running cp -R from/data/dir/* to/backup/dir/ & [2]+ Running find . -iname "*jpg" > to/backup/dir/images.txt &
fg命令可以将后台运行的任务放到前台运行,这样可以比较方便地进行交互。根据jobs命令提供的进程任务序号,再在前面加上% 符号,就可以把相应的进程任务放到前台运行。
# fg %1 #将上面序号为1的cp任务放到前台运行 cp -R from/data/dir/* to/backup/dir/
如果这个进程任务是暂停状态,fg命令会将它启动起来。至此我们知道如何将命令或任务放入后台,提取到前台运行。需要注意的是,如果这个任务有输出内容到标准输出中(例如ping, echo或ls等命令),即使使用了&,也需要等待这些输出任务在前台运行完毕,才可以做其他工作。
这时候我们如果结合nohup命令则可以将标准输出和标准错误输出重定向到no文件中。当我们退出终端或者断开SSH连接时,终端会收到HUP(hangup)信号从而关闭其所有子进程。因此,我们就可以通过让进程忽略HUP信号,也就是nohup的作用了。
# nohup ping www. & [1] 1418 # nohup: ignoring input and appending output to ‘no’
screen / tmux
我们已经知道了如何让进程免受HUP信号的影响,但是如果有大量这种命令需要在稳定的后台里运行,如何避免对每条命令都做这样的操作呢?
此时最方便的方法就是screen了。简单的说,screen 提供了ANSI/VT100的终端模拟器,使它能够在一个真实终端下运行多个全屏的伪终端。screen的参数很多,具有很强大的功能,这里我们就先了解下常用功能:
- screen -dmS session-name来建立一个处于断开模式下的会话(并指定其会话名)。
- screen -list 来列出所有会话。
- screen -r session-name来重新连接指定会话。
- 快捷键Ctrl-a d 来暂时断开当前会话。
# screen -dmS hello # screen -list There is a screen on: 8824.hello (Detached) 1 Socket in /var/run/screen/S-root. # screen -r hello
当我们用“-r”连接到screen会话后,我们就可以在这个伪终端里面为所欲为,再也不用担心HUP信号会对我们的进程造成影响,也不用给每个命令前都加上“nohup”
让我来看一下下面两个例子,看下screen是如何避免HUP信号的影响
使用&时,进程的进程树
# ping www. & [1] 9499 # pstree -H 9499 init─┬─Xvnc ├─acpid ├─atd ├─2*[sendmail] ├─sshd─┬─sshd───bash───pstree │ └─sshd───bash───ping
未使用screen时我们所处的bash是sshd的子进程,当ssh断开连接时,HUP信号自然会影响到它下面的所有子进程(包括我们建立的ping进程)。
使用screen时的进程树
# screen -r hello # ping www.ibm.com & [1] 9488 # pstree -H 9488 init─┬─Xvnc ├─acpid ├─atd ├─screen───bash───ping ├─2*[sendmail]
此时bash是screen的子进程,而screen是init(PID为1)的子进程。那么当ssh断开连接时,HUP信号自然不会影响到screen下面的子进程了。
然后tmux和screen是实现类似功能的,大家看个人爱好了解选择就好。
最后小结下,如果不需要查看程序的信息输出,并且只是相对耗时的命令任务,可以选择nohup和&的命令组合将任务放到后台执行,如果是大量的命令要在后台稳定执行,并且还经常要调到前台执行,或时常查看,那么可以使用screen或tmux建立新的session的方式来使命令或程序运行于后台。