作者:岳國(guó)帥
原文地址:http://www.linuxprobe.com/process-run-background/
想讓進(jìn)程在斷開(kāi)連接后依然保持運(yùn)行左痢?如果該進(jìn)程已經(jīng)開(kāi)始運(yùn)行了該如何補(bǔ)救屎暇? 如果有大量這類需求如何簡(jiǎn)化操作规个?
我們經(jīng)常會(huì)碰到這樣的問(wèn)題,用 telnet/ssh 登錄了遠(yuǎn)程的 Linux 服務(wù)器捌议,運(yùn)行了一些耗時(shí)較長(zhǎng)的任務(wù), 結(jié)果卻由于網(wǎng)絡(luò)的不穩(wěn)定導(dǎo)致任務(wù)中途失敗映皆。如何讓命令提交后不受本地關(guān)閉終端窗口租幕、網(wǎng)絡(luò)斷開(kāi)連接的干擾呢?
下面舉了一些例子着倾, 您可以針對(duì)不同的場(chǎng)景選擇不同的方式來(lái)處理這個(gè)問(wèn)題拾酝。
nohup/setsid/&
場(chǎng)景:
如果只是臨時(shí)有一個(gè)命令需要長(zhǎng)時(shí)間運(yùn)行,什么方法能最簡(jiǎn)便的保證它在后臺(tái)穩(wěn)定運(yùn)行呢卡者?
我們知道蒿囤,當(dāng)用戶注銷logout或者網(wǎng)絡(luò)斷開(kāi)時(shí),終端會(huì)收到 HUP(hangup)信號(hào)從而關(guān)閉其所有子進(jìn)程崇决。因此材诽,我們的解決辦法就有兩種途徑:要么讓進(jìn)程忽略 HUP 信號(hào),要么讓進(jìn)程運(yùn)行在新的會(huì)話里從而成為不屬于此終端的子進(jìn)程恒傻。
1.nohup
nohup 無(wú)疑是我們首先想到的辦法脸侥。顧名思義,nohup 的用途就是讓提交的命令忽略 hangup 信號(hào)盈厘。
nohup 的使用是十分方便的睁枕,只需在要處理的命令前加上 nohup 即可,標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤缺省會(huì)被重定向到 nohup.out 文件中。一般我們可在結(jié)尾加上"&
"來(lái)將命令同時(shí)放入后臺(tái)運(yùn)行外遇,也可用">filename 2>&1
"來(lái)更改缺省的重定向文件名注簿。
nohup 示例:
[root@pvcent107 ~]# nohup ping www.ibm.com &
[1] 3059
nohup: appending output to `nohup.out'
[root@pvcent107 ~]# ps -ef |grep 3059
root 3059 984 0 21:06 pts/3 00:00:00 ping www.ibm.com
root 3067 984 0 21:06 pts/3 00:00:00 grep 3059
[root@pvcent107 ~]#
2.setsid
nohup 無(wú)疑能通過(guò)忽略 HUP 信號(hào),來(lái)使我們的進(jìn)程避免中途被中斷跳仿。但如果我們換個(gè)角度思考诡渴,如果我們的進(jìn)程不屬于接受 HUP 信號(hào)的終端的子進(jìn)程,那么自然也就不會(huì)受到 HUP 信號(hào)的影響了菲语。setsid 就能幫助我們做到這一點(diǎn)妄辩。
setsid 的使用也是非常方便的,也只需在要處理的命令前加上 setsid 即可山上。
setsid 示例:
[root@pvcent107 ~]# setsid ping www.ibm.com
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root 31094 1 0 07:28 ? 00:00:00 ping www.ibm.com
root 31102 29217 0 07:29 pts/4 00:00:00 grep www.ibm.com
[root@pvcent107 ~]#
值得注意的是恩袱,上例中我們的進(jìn)程 ID(PID)為31094,而它的父 ID(PPID)為1(即為 init 進(jìn)程 ID)胶哲,并不是當(dāng)前終端的進(jìn)程 ID畔塔。請(qǐng)將此例與nohup 例中的父 ID 做比較。
3.&
這里還有一個(gè)關(guān)于 subshell 的小技巧鸯屿。我們知道澈吨,將一個(gè)或多個(gè)命名包含在“()
”中就能讓這些命令在子 shell 中運(yùn)行中,從而擴(kuò)展出很多有趣的功能寄摆,我們現(xiàn)在要討論的就是其中之一谅辣。
當(dāng)我們將"&
"也放入“()
”內(nèi)之后,我們就會(huì)發(fā)現(xiàn)所提交的作業(yè)并不在作業(yè)列表中婶恼,也就是說(shuō)桑阶,是無(wú)法通過(guò)jobs來(lái)查看的。讓我們來(lái)看看勾邦,為什么這樣就能躲過(guò) HUP 信號(hào)的影響吧蚣录。
subshell 示例:
[root@pvcent107 ~]# (ping www.ibm.com &)
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root 16270 1 0 14:13 pts/4 00:00:00 ping www.ibm.com
root 16278 15362 0 14:13 pts/4 00:00:00 grep www.ibm.com
[root@pvcent107 ~]#
從上例中可以看出,新提交的進(jìn)程的父 ID(PPID)為1(init 進(jìn)程的 PID)眷篇,并不是當(dāng)前終端的進(jìn)程 ID萎河。因此并不屬于當(dāng)前終端的子進(jìn)程,從而也就不會(huì)受到當(dāng)前終端的 HUP 信號(hào)的影響了蕉饼。
disown
我們已經(jīng)知道虐杯,如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信號(hào)的影響。但是如果我們未加任何處理就已經(jīng)提交了命令昧港,該如何補(bǔ)救才能讓它避免 HUP 信號(hào)的影響呢擎椰?
這時(shí)想加 nohup 或者 setsid 已經(jīng)為時(shí)已晚,只能通過(guò)作業(yè)調(diào)度和 disown 來(lái)解決這個(gè)問(wèn)題了创肥。
讓我們來(lái)看一下 disown 的幫助信息:
disown [-ar] [-h] [jobspec ...]
Without options, each jobspec is removed from the table of
active jobs. If the -h option is given, each jobspec is not
removed from the table, but is marked so that SIGHUP is not
sent to the job if the shell receives a SIGHUP. If no jobspec
is present, and neither the -a nor the -r option is supplied,
the current job is used. If no jobspec is supplied, the -a
option means to remove or mark all jobs; the -r option without
a jobspec argument restricts operation to running jobs. The
return value is 0 unless a jobspec does not specify a valid
job.
我們可以用如下方式來(lái)達(dá)成我們的目的达舒。
- 靈活運(yùn)用
CTRL-z
在我們的日常工作中值朋,我們可以用CTRL-z
來(lái)將當(dāng)前進(jìn)程掛起到后臺(tái)暫停運(yùn)行,執(zhí)行一些別的操作休弃,然后再用fg
來(lái)將掛起的進(jìn)程重新放回前臺(tái)(也可用bg
來(lái)將掛起的進(jìn)程放在后臺(tái))繼續(xù)運(yùn)行。這樣我們就可以在一個(gè)終端內(nèi)靈活切換運(yùn)行多個(gè)任務(wù)圈膏,這一點(diǎn)在調(diào)試代碼時(shí)尤為有用塔猾。因?yàn)閷⒋a編輯器掛起到后臺(tái)再重新放回時(shí),光標(biāo)定位仍然停留在上次掛起時(shí)的位置稽坤,避免了重新定位的麻煩丈甸。
用disown -h jobspec來(lái)使某個(gè)作業(yè)忽略HUP信號(hào)。
用disown -ah 來(lái)使所有的作業(yè)都忽略HUP信號(hào)尿褪。
用disown -rh 來(lái)使正在運(yùn)行的作業(yè)忽略HUP信號(hào)睦擂。
需要注意的是,當(dāng)使用過(guò) disown 之后杖玲,會(huì)將把目標(biāo)作業(yè)從作業(yè)列表中移除顿仇,我們將不能再使用jobs
來(lái)查看它,但是依然能夠用ps -ef
查找到它摆马。
但是還有一個(gè)問(wèn)題臼闻,這種方法的操作對(duì)象是作業(yè),如果我們?cè)谶\(yùn)行命令時(shí)在結(jié)尾加了"&
"來(lái)使它成為一個(gè)作業(yè)并在后臺(tái)運(yùn)行囤采,那么就萬(wàn)事大吉了述呐,我們可以通過(guò)jobs
命令來(lái)得到所有作業(yè)的列表。
但是如果并沒(méi)有把當(dāng)前命令作為作業(yè)來(lái)運(yùn)行乓搬,如何才能得到它的作業(yè)號(hào)呢棉磨?答案就是用CTRL-z
(按住Ctrl
鍵的同時(shí)按住z
鍵)了频敛!
CTRL-z
的用途就是將當(dāng)前進(jìn)程掛起Suspend
差油,然后我們就可以用jobs
命令來(lái)查詢它的作業(yè)號(hào)发侵,再用bg jobspec
來(lái)將它放入后臺(tái)并繼續(xù)運(yùn)行盅弛。
需要注意的是,如果掛起會(huì)影響當(dāng)前進(jìn)程的運(yùn)行結(jié)果,請(qǐng)慎用此方法。
disown 示例1:(如果提交命令時(shí)已經(jīng)用“&
”將命令放入后臺(tái)運(yùn)行,則可以直接使用“disown
”)
[root@pvcent107 build]# cp -r testLargeFile largeFile &
[1] 4825
[root@pvcent107 build]# jobs
[1]+ Running cp -i -r testLargeFile largeFile &
[root@pvcent107 build]# disown -h %1
[root@pvcent107 build]# ps -ef |grep largeFile
root 4825 968 1 09:46 pts/4 00:00:00 cp -i -r testLargeFile largeFile
root 4853 968 0 09:46 pts/4 00:00:00 grep largeFile
[root@pvcent107 build]# logout
disown 示例2:(如果提交命令時(shí)未使用“&
”將命令放入后臺(tái)運(yùn)行气忠,可使用CTRL-z
和“bg
”將其放入后臺(tái),再使用“disown
”)
[root@pvcent107 build]# cp -r testLargeFile largeFile2
[1]+ Stopped cp -i -r testLargeFile largeFile2
[root@pvcent107 build]# bg %1
[1]+ cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build]# jobs
[1]+ Running cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build]# disown -h %1
[root@pvcent107 build]# ps -ef |grep largeFile2
root 5790 5577 1 10:04 pts/3 00:00:00 cp -i -r testLargeFile largeFile2
root 5824 5577 0 10:05 pts/3 00:00:00 grep largeFile2
[root@pvcent107 build]#
screen
我們已經(jīng)知道了如何讓進(jìn)程免受 HUP 信號(hào)的影響,但是如果有大量這種命令需要在穩(wěn)定的后臺(tái)里運(yùn)行,如何避免對(duì)每條命令都做這樣的操作呢?
此時(shí)最方便的方法就是 screen 了身辨。簡(jiǎn)單的說(shuō)号俐,screen 提供了 ANSI/VT100 的終端模擬器洗贰,使它能夠在一個(gè)真實(shí)終端下運(yùn)行多個(gè)全屏的偽終端绎晃。screen 的參數(shù)很多杂曲,具有很強(qiáng)大的功能庶艾,我們?cè)诖藘H介紹其常用功能以及簡(jiǎn)要分析一下,為什么使用 screen 能夠避免 HUP 信號(hào)的影響擎勘。我們先看一下 screen 的幫助信息:
SCREEN(1) SCREEN(1)
NAME
screen - screen manager with VT100/ANSI terminal emulation
SYNOPSIS
screen [ -options ] [ cmd [ args ] ]
screen -r [[pid.]tty[.host]]
screen -r sessionowner/[[pid.]tty[.host]]
DESCRIPTION
Screen is a full-screen window manager that multiplexes a physical
terminal between several processes (typically interactive shells).
Each virtual terminal provides the functions of a DEC VT100 terminal
and, in addition, several control functions from the ISO 6429 (ECMA
48, ANSI X3.64) and ISO 2022 standards (e.g. insert/delete line and
support for multiple character sets). There is a scrollback history
buffer for each virtual terminal and a copy-and-paste mechanism that
allows moving text regions between windows.
使用 screen 很方便咱揍,有以下幾個(gè)常用選項(xiàng):
用screen -dmS session name來(lái)建立一個(gè)處于斷開(kāi)模式下的會(huì)話(并指定其會(huì)話名)。
用screen -list 來(lái)列出所有會(huì)話棚饵。
用screen -r session name來(lái)重新連接指定會(huì)話煤裙。
用快捷鍵CTRL-a d 來(lái)暫時(shí)斷開(kāi)當(dāng)前會(huì)話。
screen 示例:
[root@pvcent107 ~]# screen -dmS Urumchi
[root@pvcent107 ~]# screen -list
There is a screen on:
12842.Urumchi (Detached)
1 Socket in /tmp/screens/S-root.
[root@pvcent107 ~]# screen -r Urumchi
當(dāng)我們用“-r
”連接到 screen 會(huì)話后噪漾,我們就可以在這個(gè)偽終端里面為所欲為硼砰,再也不用擔(dān)心 HUP 信號(hào)會(huì)對(duì)我們的進(jìn)程造成影響,也不用給每個(gè)命令前都加上“nohup
”或者“setsid
”了欣硼。這是為什么呢题翰?讓我來(lái)看一下,下面兩個(gè)例子吧诈胜。
1.未使用 screen 時(shí)新進(jìn)程的進(jìn)程樹(shù):
[root@pvcent107 ~]# ping www.google.com &
[1] 9499
[root@pvcent107 ~]# pstree -H 9499
init─┬─Xvnc
├─acpid
├─atd
├─2*[sendmail]
├─sshd─┬─sshd───bash───pstree
│ └─sshd───bash───ping
我們可以看出豹障,未使用 screen 時(shí)我們所處的bash
是sshd
的子進(jìn)程,當(dāng)ssh
斷開(kāi)連接時(shí)焦匈,HUP
信號(hào)自然會(huì)影響到它下面的所有子進(jìn)程(包括我們新建立的 ping 進(jìn)程)沼填。
2.使用了 screen 后新進(jìn)程的進(jìn)程樹(shù):
[root@pvcent107 ~]# screen -r Urumchi
[root@pvcent107 ~]# ping www.ibm.com &
[1] 9488
[root@pvcent107 ~]# pstree -H 9488
init─┬─Xvnc
├─acpid
├─atd
├─screen───bash───ping
├─2*[sendmail]
而使用了 screen 后就不同了,此時(shí)bash
是screen
的子進(jìn)程括授,而 screen
是init
(PID為1)的子進(jìn)程坞笙。那么當(dāng)ssh
斷開(kāi)連接時(shí)岩饼,HUP
信號(hào)自然不會(huì)影響到screen
下面的子進(jìn)程了。
總結(jié)
現(xiàn)在幾種方法已經(jīng)介紹完畢薛夜,我們可以根據(jù)不同的場(chǎng)景來(lái)選擇不同的方案籍茧。nohup/setsid
無(wú)疑是臨時(shí)需要時(shí)最方便的方法,disown
能幫助我們來(lái)事后補(bǔ)救當(dāng)前已經(jīng)在運(yùn)行了的作業(yè)梯澜,而screen
則是在大批量操作時(shí)不二的選擇了寞冯。