如何讓shell指令碼自殺,shell指令碼自殺
有些時候我們寫的shell指令碼中有一些背景工作,當指令碼的流程已經執行到結尾處並退出時,這些背景工作會直接掛靠在init/systemd進程下,而不會隨著指令碼退出而停止。
例如:
[root@mariadb ~]# cat test1.sh #!/bin/bashecho $BASHPIDsleep 50 &[root@mariadb ~]# ps -elf | grep slee[p]0 S root 10806 1 0 80 0 - 26973 hrtime 19:26 pts/1 00:00:00 sleep 50
從結果中可以看到,指令碼退出後,sleep進程的父進程變為了1,也就是掛在了init/systemd進程下。
這時我們可以在指令碼中直接使用kill命令殺掉sleep進程。
[root@mariadb ~]# cat test1.sh #!/bin/bashecho $BASHPIDsleep 50 &kill $!
但是,如果這個sleep進程是在迴圈中,那就麻煩了。
例如下面的例子,殺掉sleep、或者殺掉指令碼自身進程、或者讓指令碼自動結束、甚至exec退出當前指令碼shell都是無效的。
[root@mariadb ~]# cat test1.sh #!/bin/bashecho $BASHPIDwhile true;do sleep 50 echo 1done &killall sleepkill $BASHPID
因為sleep在while中迴圈,殺了sleep後,稍後又會產生一個sleep。而殺掉指令碼自身、或者讓指令碼自動結束、或者使用exec,由於有迴圈存在,它都會重新fork一個指令碼進程出來。注意,這時迴圈的進程不會掛在init/systemd進程下,而是掛在一個新的指令碼進程之下。
[root@mariadb ~]# ./test1.sh 10859./test1.sh: line 7: 10862 Terminated sleep 50Terminated1[root@mariadb ~]# pstree -p | grep sleep |-test1.sh(10860)---sleep(10863)
從結果中可以看到test1.sh的10859進程被自身殺掉了,但是重建了一個10860的test1.sh進程,且不斷產生的sleep進程也總是在test1.sh下。
除非我們手動殺掉新產生的test1.sh,否則這個指令碼將無限迴圈下去。但是,這不是很麻煩嗎?
那麼如何?"指令碼自殺"?其實很簡單,只要在指令碼退出前,使用killall命令殺掉指令碼進程即可。
[root@mariadb ~]# cat test1.sh #!/bin/bashecho $BASHPIDwhile true;do sleep 50 echo 1done &killall `basename $0`
這樣,在指令碼退出前,核心準備fork新的test1.sh進程接管背景while內的sleep進程時,killall會將這個新的test1.sh也殺掉,這樣後台進程就隨著test1.sh也一起消逝了。
這裡的關鍵點是,當指令碼中有迴圈的背景工作時,指令碼退出有一個過程:(1)指令碼準備退出-->(2)核心fork新的指令碼進程用來接管指令碼內的後台迴圈任務-->(3)新指令碼進程接管背景工作-->(4)舊指令碼進程消逝。而killall正好趕在第(3)步之前將新舊指令碼進程都殺掉,這使得指令碼進程成功自殺。
回到Linux系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7048359.html
回到網站架構系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7576137.html
回到資料庫系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7586194.html
轉載請註明出處:http://www.cnblogs.com/f-ck-need-u/p/8661501.html
註:若您覺得這篇文章還不錯請點擊右下角推薦,您的支援能激發作者更大的寫作熱情,非常感謝!