Linux 后台运行程序
在 Linux 系统中的终端工作时,有时需要将当前任务暂停调至后台,或有时须将后台暂停的任务重新开启并调至前台,这一序列的操作将会使用到 jobs、bg、和 fg 三个命令。
jobs
jos
命令用于显示 Linux 中的任务列表及任务状态,包括后台运行的任务。该命令可以显示任务号及其对应的进程号。其中,任务号是以普通用户的角度进行的,而进程号则是从系统管理员的角度来看的。一个任务可以对应于一个或者多个进程号。
$ jobs
[1]- stopped ping -c 10 baidu.com
[2]+ stopped ping -c 10 taobao.com
[3] running ping -c 10000 localhost > /dev/null 2>&1 &
$ jobs -l # 显示进程号
[1]- 22703 stopped ping -c 10 baidu.com
[2]+ 22810 stopped ping -c 10 taobao.com
[3] 24148 running ping -c 10000 localhost > /dev/null 2>&1 &
$ jobs -r # 仅列出正在运行的进程
[3] running ping -c 10000 localhost > /dev/null 2>&1 &
$ jobs -s # 仅列出暂停的进程
[1] - suspended ping -c 10 baidu.com
[2] + suspended ping -c 10 taobao.com
输出结果中的 +
表示是当前默认作业,-
减号表示是下一个默认作业。最前的需要为作业号。
要杀死一些后台作业,可以用 kill %jobnum
,或者找到进程号,再用 kill pid
杀掉。
&
如果需要在后台运行一个进程,可以在运行的命令后边加上 &
。这样做只能让进程让出当前的终端以便做其他的事,但如果后台运行的进程有输出,仍然会打印到屏幕上,这样会干扰当前的工作。而且即使进程在后台运行,如果终端被关闭,该进程仍然会被杀掉。
‘ctrl-z’ 与 ‘bg’
快捷键 ctrl-z
能将进程放到后台运行,但进程会先处于暂停状态(suspended)。此时用 bg
命令将一个在后台暂停的命令,变成继续执行。所以要将一个前台正在运行的进程放入后台运行的步骤是:
- 先按组合键
ctrl-z
将其挂起 - 再用
bg
命名使其继续运行(可以直接使用 bg 命令不加任何参数,最后放入后台的作业会被标记为默认要运行的作业)
需要注意的是,如果挂起可能会影响当前进程的运行结果,需慎用。
$ ping baidu.com
PING baidu.com (39.156.69.79) 56(84) bytes of data.
64 bytes from 39.156.69.79: icmp_seq=1 ttl=52 time=4.69 ms
64 bytes from 39.156.69.79: icmp_seq=2 ttl=52 time=4.58 ms
^Z
[1]+ stopped ping -c 10 baidu.com
$ bg
[2]+ ping -c 10 taobao.com &
64 bytes from 140.205.220.96: icmp_seq=3 ttl=49 time=20.9 ms
64 bytes from 140.205.220.96: icmp_seq=4 ttl=49 time=20.7 ms
$ jobs
[1]+ stopped ping -c 10 baidu.com
[3]- running ping -c 10 -c 10000 localhost > /dev/null 2>&1 &
$ bg %1
[1]+ ping -c 10 baidu.com &
64 bytes from 39.156.69.79: icmp_seq=3 ttl=52 time=4.73 ms
64 bytes from 39.156.69.79: icmp_seq=4 ttl=52 time=4.56 ms
$ jobs
[3]+ running ping -c 10 -c 10000 localhost > /dev/null 2>&1 &
fg
fg
命令用于将后台作业(在后台运行的或者在后台挂起的作业)放到前台终端运行。
$ fg %3
ping -c 10 -c 10000 localhost > /dev/null 2>&1
nohup
当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。也就是任何在终端启动的正在运行的进程都会停止。很多时候,我们会通过 ssh 远程连接服务器来工作,在网络状况很糟糕的情况下,一段网络中断我们的工作就会被打断。如果我们正在进行一项很重要的工作,这无疑是个灾难。
nohup
命令可以让提交的命令忽略 hangup 信号。标准输出和标准错误缺省会被重定向到 nohup.out 文件中。但是用 nohub 启动的进程仍然在前台运行,不会让出终端。
一般我们可在结尾加上 &
来将命令同时放入后台运行,也可用 >filename 2>&1
来更改缺省的重定向文件名。这样进程既可以不被 hangup 信号打断,又能够将终端让出。例如在后台执行耗时的 du 命令:
nohub du sh /* | sort -h > /tmp/du.log 2>&1 &
nohup
无疑能通过忽略 HUP 信号来使我们的进程避免中途被中断。2>&1
的作用是将标准错误 2 重定向到标准输出 1 中。此处 1 前面的 &
就是为了让 shell 将 1 解释成标准输出而不是文件 1。
在 shell 中 0,1,2 三个数字分别代表 STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,即标准输入(一般是键盘),标准输出(一般是显示屏,准确的说是用户终端控制台),标准错误(出错信息输出)。
默认输入只有一个输入(0,STDIN_FILENO),而默认输出有两个(标准输出1 STDOUT_FILENO,标准错误2 STDERR_FILENO)。因此默认情况下,shell 输出的错误信息会被输出到 2,而普通输出信息会输出到 1。
setsid
如果我们的进程不属于接受 HUP 信号的终端的子进程,那么自然也就不会受到 HUP 信号的影响了。setsid
就能帮助我们做到这一点。setsid 用于在一个新的会话中运行程序, 其父进程为 init
。
示例:
setsid ping www.baidu.com
disown
如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信号的影响,但是如果我们未加任何处理就已经提交了命令,该如何补救才能让它避免 HUP 信号的影响呢?
这种情况我们可以用 disown 并配置作业调度来让进程忽略 HUB 信号。使用方法:
disown -h %1 使某个作业忽略 HUP 信号, 1 为作业号
disown -ah 使所有的作业都忽略 HUP 信号
disown -rh 使正在运行的作业忽略 HUP 信号
screen
Screen
是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。Screen 中有会话的概念,会话可以保持你的工作,即使网络断开会话仍然被保存,这样便可以保证运行的程序不被打断。而且还可以创建多个会话,并在不同会话间切换。类似的工具还要 tmux、dvtm、splitvt、byobu 等。