shell的后臺運行(&)與nohup
簡述
在shell腳本中當我們需要把一個任務放在后臺運行時嘁信,通常我們會使用&符號:
subcommand &
此時主進程會繼續(xù)往下執(zhí)行话速,而子進程會在后臺啟動運行。
于此同時塌碌,我們常會看到nohup會和后臺任務一起使用,格式是:
nohup subcommand &
nohup在這里起了什么角色呢浇揩。
nohup
nohup起兩個作用:
- 正如名字所聲稱的熊昌,忽略所有發(fā)送給子命令的掛斷(SIGHUP)信號
nohup subcommand &
這樣所有發(fā)給subcommand的SIGHUP信號都被忽略绽榛,subcommand就不會收到SIGHUP信號。
什么是SIGHUP信號呢婿屹?
簡單的理解可以是終端結束時灭美,操作系統(tǒng)會發(fā)送SIGHUP信號到后臺進程。
- 重定向子命令的標準輸出(stdout)和標準錯誤(stderr)
我們可以在終端看到如下輸出:
nohup: appending output to "nohup.out"
表示subcommand的標準輸出和標準錯誤被重定向到nohup.out文件昂利;如果沒有使用nohup方式届腐,則subcommand的標準輸出和標準錯誤是復用父進程的標準輸出和標準錯誤铁坎。
舉例
例子1:后臺運行(&)
$ cat testshell0.sh
#!/bin/bash
#trap "echo \"SIGHUP is received\"" 1
for i in {1..10000}; do
echo "$i: in $0"
1>&2 echo "$i: in $0"
sleep 1
done
$ cat testshell1.sh
#!/bin/bash
./testshell0.sh &
for i in {1..10000}; do
echo "$i: in $0"
sleep 1
done
$ ./testshell1.sh
1: in ./testshell1.sh
1: in ./testshell0.sh
1: in ./testshell0.sh
2: in ./testshell1.sh
2: in ./testshell0.sh
2: in ./testshell0.sh
CTRL-C(^C)
$ 3: in ./testshell0.sh
3: in ./testshell0.sh
4: in ./testshell0.sh
5: in ./testshell0.sh
腳本testshell1.sh以后臺方式(&)調用testshell0.sh;
我們看到testshell1.sh和testshell0.sh的輸出都在屏幕上犁苏,而當(CTRL-C)殺掉testshell1.sh的時候硬萍,testshell0.sh繼續(xù)在運行,繼續(xù)往屏幕打印輸出围详。
例子2:nohup方式后臺運行(&)
$ cat testshell0.sh
#!/bin/bash
#trap "echo \"SIGHUP is received\"" 1
for i in {1..10000}; do
echo "$i: in $0"
1>&2 echo "$i: in $0"
sleep 1
done
$ cat testshell1.sh
#!/bin/bash
nohup ./testshell0.sh &
for i in {1..10000}; do
echo "$i: in $0"
sleep 1
done
$ ./testshell1.sh
nohup: appending output to "nohup.out"
1: in ./testshell1.sh
1: in ./testshell0.sh
1: in ./testshell0.sh
2: in ./testshell1.sh
2: in ./testshell0.sh
2: in ./testshell0.sh
CTRL-C(^C)
$
腳本testshell1.sh以nohup的方式在后臺(&)調用testshell0.sh朴乖;
我們看到testshell1.sh的輸出在屏幕上,testshell0.sh的輸出在文件nohup.out里:
$ tail -f nohup.out
1: in ./testshell0.sh
1: in ./testshell0.sh
2: in ./testshell0.sh
2: in ./testshell0.sh
3: in ./testshell0.sh
3: in ./testshell0.sh
而當(CTRL-C)殺掉testshell1.sh的時候助赞,testshell0.sh繼續(xù)在運行买羞,繼續(xù)往nohup.log里面打印輸出。
在這兩個例子中雹食,當testshell1.sh已經停止時畜普,testshell0.sh并不會結束,而都能繼續(xù)運行婉徘。
例子3:后臺運行(&) + 關閉終端
代碼和運行方法同例子1漠嵌,只是在運行時關閉終端。
結果testshell1.sh和testshell0.sh都結束了盖呼。
$ ps -ef | grep testshell | grep -v grep
$
例子4:nohup方式后臺運行(&) + 關閉終端
代碼和運行方法同例子2儒鹿,只是在運行時關閉終端。
結果testshell1.sh結束了几晤,而testshell0.sh還在繼續(xù)運行约炎。
$ ps -ef | grep testshell | grep -v grep
<uid> <pid> 1 0 22:29 ? 00:00:00 /bin/bash ./testshell0.sh
$
需要注意的是,此時testshell0.sh的父進程變成了進程號1蟹瘾,而不是testshell1.sh圾浅,因為testshell1.sh已經死了,操作系統(tǒng)接管了testshell1.sh進程憾朴。
對比例子3和例子4狸捕,差別是是否以nohup的方式運行testshell0.sh,在例子3不是以nohup的方式众雷,這樣當終端結束的時候灸拍,testshell0.sh會收到SIGHUP信號,缺省的處理方式是殺掉自己砾省,所以testshell0.sh也死了鸡岗;而例子4使用了nohup方式,他會忽略SIGHUP信號编兄,所以testshell0.sh繼續(xù)運行轩性。
看例子5,注意其中的區(qū)別
例子5:后臺運行(&) + 關閉父進程+關閉終端
代碼和運行方法同例子1狠鸳。
啟動進程testshell1.sh
$ ./testshell1.sh
1: in ./testshell1.sh
1: in ./testshell0.sh
1: in ./testshell0.sh
2: in ./testshell1.sh
2: in ./testshell0.sh
2: in ./testshell0.sh
3: in ./testshell1.sh
3: in ./testshell0.sh
3: in ./testshell0.sh
此時testshell1.sh和testshell0.sh同時在運行揣苏,往終端打印輸出悯嗓。
$ ps -ef | grep testshell | grep -v grep
<uid> 13789 13642 0 22:34 pts/10 00:00:00 /bin/bash ./testshell1.sh
<uid> 13790 13789 0 22:34 pts/10 00:00:00 /bin/bash ./testshell0.sh
殺掉進程testshell1.sh
屏幕繼續(xù)打印testshell0.sh的輸出。
CTRL-C(^C)
$ 4: in ./testshell0.sh
4: in ./testshell0.sh
5: in ./testshell0.sh
5: in ./testshell0.sh
查看進程狀態(tài)
$ ps -ef | grep testshell | grep -v grep
<uid> 13790 1 0 22:34 pts/10 00:00:00 /bin/bash ./testshell0.sh
$
子進程testshell0.sh繼續(xù)在運行舒岸。
此時我們退出終端绅作,再查看進程狀態(tài)
$ ps -ef | grep testshell | grep -v grep
<uid> 13790 1 0 22:34 pts/10 00:00:00 /bin/bash ./testshell0.sh
$
為什么子進程testshell0.sh還在呢?
既然終端已經退出了蛾派,按理操作系統(tǒng)應該給testshell0.sh發(fā)送SIGHUP信號俄认,然后導致testshell0.sh退出啊洪乍?
原因是testshell0.sh是以后臺任務的方式由testshell1.sh提交眯杏,當testshell1.sh已經退出后,testshell0.sh變成了孤兒進程壳澳,操作系統(tǒng)自動收集這些孤兒進程岂贩,此時我們看到testshell0.sh的父進程已經變成進程號1了,這樣testshell0.sh和當前終端已經沒有了關系巷波,他們失去了聯(lián)系萎津,從而當當前終端結束的時候,testshell0.sh不會也不需要得到什么消息抹镊,那么也就不會收到SIGHUP信號了锉屈。
這鏈接里面[SIGHUP信號與控制終端]https://blog.csdn.net/cugxueyu/article/details/2046565,非常清楚的介紹了兩者的關系垮耳,供參考颈渊。