在linux上進行測試時發現啟動后台進程后,如果使用exit退出登錄shell,shell退出后后台進程還是能夠正常運行,但如果直接關閉登陸的窗口(如直接關掉xshell),那后台進程就會一起終了。都是退出登錄為什么前者后台進程會退出,而后者不會退出呢?
在查看bash的manual時發現有如下一段描述:
The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP.
由此可以知道后台進程退出是由於登陸shell收到了SIGHUP信號后在退出前將SIGHUP轉發給所有的作業(jobs)。jobs由於收到SIGHUP而終止運行。
那能不能通過設置,在窗口異常關閉時保持后台進程繼續運行呢?
答案是肯定的,一般有如下4種方法:
(在此聲明,推薦使用exit退出,以下方法不一定管用,網上找的方法,未測試;第一種方法可能對一些進程有效,一些無效吧,至少我測試過,elasticsearch的kibana進程,nohup是無法阻止SIGHUP信號的)
1. 使用nohup運行命令
# nohup ./back.sh & # nohup ./fore.sh ^Z [2]+ Stopped nohup ./fore.sh # jobs [1]- Running nohup ./back.sh & [2]+ Stopped nohup ./fore.sh # ps -o pid,ppid,pgid,sid,cmd PID PPID PGID SID CMD 4766 4716 4766 4716 /bin/bash ./back.sh 4769 4716 4769 4716 /bin/bash ./fore.sh # fg nohup ./fore.sh ### 關閉窗口並重新登錄 ### # ps -eo pid,paid,pgid,sid,cmd |grep -E "back|fore" 4766 1 4766 4716 /bin/bash ./back.sh 4769 1 4769 4716 /bin/bash ./fore.sh
發現重新登錄后前台和后台進程都還運行着但父進程變成了init。
值得注意的是nohup會在當前目錄下產生一個nohup.out文件,並把實際命令的標准輸出和標准錯誤重定向為nohup.out
2. 使用setsid運行命令
# setsid ./back.sh & # setsid ./fore.sh # jobs # ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore" 4871 1 4871 4871 /bin/bash ./back.sh 4874 1 4874 4874 /bin/bash ./fore.sh ### 關閉窗口並重新登錄 ### # ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore" 4871 1 4871 4871 /bin/bash ./back.sh 4874 1 4874 4874 /bin/bash ./fore.sh
可以發現在使用setsid后,不能在當前登錄shell的jobs中找到back.sh和fore.sh。並且由於在退出前back.sh和fore.sh的父進程已經是init,重新登錄后back.sh和fore.sh沒有發生任何改變。
3. 使用disown命令
# ./fore.sh ^Z [2]+ Stopped # jobs [1]- Running ./back.sh & [2]+ Stopped ./fore.sh # ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore" 5395 5361 5395 5361 /bin/bash ./back.sh 5396 5361 5396 5361 /bin/bash ./fore.sh # disown -h %2 # disown -a %1 # jobs [2]+ Stopped ./fore.sh # fg ./fore.sh ### 關閉窗口並重新登錄 ### # ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore" 5395 5361 5395 5361 /bin/bash ./back.sh
重新登錄后發現fore.sh還是被終止了,並且經過調查發現終了的原因是收到了SIGHUP信號。由此可見disown僅對后台進程起作用。
4. Catch SIGHUP信號
如果是shell腳本,則在腳本中加上下面的一條語句就行了。
# trap "" HUP
如果是C程序,則使用signal函數對SIGHUP進行屏蔽就行了。
signal(SIGHUP, SIG_IGN);
X. 當然相反的我們也可以讓shell在exit退出時發送SIGHUP給所有的jobs,具體設置如下:
# shopt -s huponexit
