亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標(biāo)題: 關(guān)于這個shell為什么沒有停止 [打印本頁]

作者: homerzhou    時間: 2015-10-27 17:36
標(biāo)題: 關(guān)于這個shell為什么沒有停止
本帖最后由 homerzhou 于 2015-10-27 17:38 編輯

我有一個test.sh,內(nèi)容如下:
  1. #!/bin/sh
  2. while true
  3. do
  4.     ping baidu.com
  5. done
復(fù)制代碼
我運行./test.sh 然后使用 ctrl + c ,可是test.sh沒有終止,ping終止了,由于循環(huán),ping之后又運行了,在網(wǎng)上查到ping是捕捉SIGINT信號的

我理解 ctrl + c 是向前臺進程組發(fā)送 SIGINT信號的,即使ping捕捉了SIGINT信號,test.sh 也應(yīng)該能終止

如果把ping 改成 sleep ,就沒有這個問題了,求高手請教
作者: yjh777    時間: 2015-10-28 00:22
按住 Ctr+C 不要松手
作者: homerzhou    時間: 2015-10-28 17:25
其實我關(guān)心的不是用什么辦法停下來,是為什么會出現(xiàn)這個情況 回復(fù) 2# yjh777


   
作者: yjh777    時間: 2015-10-28 18:05
我的理解是這樣:因為你只安一次 Ctr+C 只發(fā)一個信號給前臺進程,如果這是正好是ping占據(jù)前臺執(zhí)行, 就是ping收到信號停止,
但是循環(huán)語句沒有停,因為循環(huán)耗時很少 所以碰到ping在執(zhí)行的概率很大。
如果連續(xù)按多次,從ping停掉,到下一個ping產(chǎn)生之前,bash在前臺 這時收到信號就會終止 當(dāng)前循環(huán)語句

如果在 ping 后面插入一個其他語句比較容易發(fā)現(xiàn)差異:
while :; do
        ping localhost
        /usr/bin/sleep 1
done

BTW: 發(fā)現(xiàn)在一個單核的VBox虛擬機上,如果沒有插入sleep 1,即使連續(xù)按Ctr+C 也無法使腳本停下來
物理機上測試行為都類似,連續(xù)按總能停下來
作者: homerzhou    時間: 2015-10-29 09:47
你好,其實我產(chǎn)生這個以為是在看一篇文檔的時候遇到的,由于我沒有權(quán)限發(fā)送網(wǎng)址,所以我這邊就截取那邊的一段
  1. 5. Special Note On SIGINT

  2. If you choose to set up a handler for SIGINT (rather than using the EXIT trap), you should be aware that a process that exits in response to SIGINT should kill itself with SIGINT rather than simply exiting, to avoid causing problems for its caller. Thus:


  3. trap 'rm -f "$tempfile"; trap - INT; kill -INT $' INT
  4. We can see the difference between a properly behaving process and a misbehaving process. On most operating systems, ping is an example of a misbehaving process. It traps SIGINT in order to display a summary at the end, before exiting. But it fails to kill itself with SIGINT, and so the calling shell does not know that it should abort as well. For example,


  5. # Bash.  Linux ping syntax.
  6. for i in {1..254}; do
  7.   ping -c 2 192.168.1.$i
  8. done
  9. Here, if the user presses Ctrl-C during the loop, it will terminate the current ping command, but it will not terminate the loop. This is because Linux's ping command does not kill itself with SIGINT in order to communicate to the caller that the SIGINT was fatal. (Linux is not unique in this respect; I do not know of any operating system whose ping command exhibits the correct behavior.)

  10. A properly behaving process such as sleep does not have this problem:


  11. i=1
  12. while [ $i -le 100 ]; do
  13.   printf "%d " $i
  14.   i=$((i+1))
  15.   sleep 1
  16. done
  17. echo
  18. If we press Ctrl-C during this loop, sleep will receive the SIGINT and die from it (sleep does not catch SIGINT). The shell sees that the sleep died from SIGINT. In the case of an interactive shell, this terminates the loop. In the case of a script, the whole script will exit, unless the script itself traps SIGINT.
復(fù)制代碼
回復(fù) 4# yjh777


   
作者: homerzhou    時間: 2015-10-29 10:11
我覺得出現(xiàn)ctrl + c 無效,并不和ping是不是正在執(zhí)行有關(guān),而是和ping捕捉信號有關(guān),因為如果把ping修改為sleep 2000,其實sleep也是一直在運行,可是這時只要按一次ctrl + c 就能停止test.sh運行,而且我覺得 ctrl + c 是發(fā)給前臺進程組,不是單單一個前臺進程的回復(fù) 4# yjh777


   
作者: yjh777    時間: 2015-10-29 11:55
homerzhou 發(fā)表于 2015-10-29 10:11
我覺得出現(xiàn)ctrl + c 無效,并不和ping是不是正在執(zhí)行有關(guān),而是和ping捕捉信號有關(guān),因為如果把ping修改為sleep 2000,其實sleep也是一直在運行,可是這時只要按一次ctrl + c 就能停止test.sh運行,而且我覺得 ctrl + c 是發(fā)給前臺進程組,不是單單一個前臺進程的


嗯,也不是進程組,就是前臺進程;但確實跟該進程是否處理 信號有關(guān);

根據(jù)你粘貼的文檔,應(yīng)該是兩種:
    1. 程序接收到 SIGINT 異常退出,這是他的父進程也會接收到相應(yīng)子進程異常退出的信號,然后一起退出;比如 sleep
    2. 進程里面對 SIGINT 處理函數(shù)做了注冊,收到信號后正常 exit,這是不影響父進程 循環(huán)繼續(xù)執(zhí)行

所以有的循環(huán)你一個 Ctr+C 就全到停掉了
而如果循環(huán)體有處理 SIGINT, 你就需要分別給 子進程和父進程 發(fā)信號,讓他們都停下來
作者: yjh777    時間: 2015-10-29 12:09
不是很確定 如果說的不對,請糾正我,非常感謝!
    回去溫習(xí)一下APUE~
作者: homerzhou    時間: 2015-10-29 16:33
本帖最后由 homerzhou 于 2015-10-29 16:34 編輯

很開心能不厭其煩的回答我的問題
我重新找了一遍APUE關(guān)于 控制終端的那一節(jié),里面有寫到 ctrl + c 是發(fā)送給前臺進程組中所有進程的,
關(guān)于你說的第一點,父進程接收到子進程異常退出 而退出,我覺得是不成立的,我覺得子進程異常退出如果沒有人為的發(fā)送信號,那么默認(rèn)的應(yīng)該就是發(fā)送信號SIGCHLD,這個信號不會是導(dǎo)致父進程退出。而且在 那篇文檔中講到 正確的做法應(yīng)該是
  1. trap 'rm -f "$tempfile"; trap - INT; kill -INT
復(fù)制代碼
,我理解這個shell的意思是當(dāng)捕捉到 SIGINT信號后,處理一下,接著把SIGINT的信號處理方式設(shè)置成默認(rèn),再給自己發(fā)送SIGINT信號,并沒有給父進程發(fā)送SIGINT信號
我把 這篇文檔網(wǎng)址(有一些空格)發(fā)給你 http : // mywiki. wooledge. org / SignalTrap 回復(fù) 8# yjh777



   
作者: yjh777    時間: 2015-10-29 17:58
嗯,我也找APUE看了一下,確實是發(fā)給進程組;而且看了一下不管是 ping 還是 sleep,兩個腳本的進程組ID都是父進程shell的進程ID;
謝謝分享鏈接。

不過到底是什么原因?qū)е掠胮ing的時候,Ctr+C 無法停掉shell進程呢???
    這個從那個文檔里還是沒有看太明白,,有事先撤了,回頭再研究研究;

@homerzhou
  如果有新的發(fā)現(xiàn),請分享你的成果,謝謝啦
作者: sncchen    時間: 2015-10-30 00:18
找到一篇文章講解的不錯:
https://  blog.robotshell.org/2012/necessary-details-about-signal-trap-in-shell

他也提到了樓主說的文檔:
http://  mywiki.wooledge.org/SignalTrap

梳理下原因:

1、
Bash 等終端的默認(rèn)行為是這樣的:當(dāng)按下 CTRL-C 之后,它會向當(dāng)前的整個進程組發(fā)出 SIGINT 信號。而 sleep 是由當(dāng)前腳本調(diào)用的,是這個腳本的子進程,默認(rèn)是在同一個進程組的,所以也會收到 SIGINT 并停止執(zhí)行


2、
這篇文檔給了我們一個更準(zhǔn)確的說明——如果當(dāng)前正有一個外部命令在前臺執(zhí)行,那么 trap 會等待當(dāng)前命令結(jié)束以后再處理信號隊列中的信號。


3、
On most operating systems, ping is an example of a misbehaving process. It traps SIGINT in order to display a summary at the end, before exiting. But it fails to kill itself with SIGINT, and so the calling shell does not know that it should abort as well


這個問題挺有趣兒的,學(xué)習(xí)了。

作者: homerzhou    時間: 2015-10-30 10:54
本帖最后由 homerzhou 于 2015-10-30 10:56 編輯

還是有一個小的疑惑,那篇文檔中提到  “如果當(dāng)前正有一個外部命令在前臺執(zhí)行,那么 trap 會等待當(dāng)前命令結(jié)束以后再處理信號隊列中的信號。”  ,不管怎么樣./test.sh 還是會收到SIGINT的信號,即使需要等到ping結(jié)束之后,那為什么這個時候收到SIGINT信號就沒有停止呢,
“But it fails to kill itself with SIGINT, and so the calling shell does not know that it should abort as well”
我是這么理解這句話的意思的,當(dāng)按ctrl +c 時,如果子進程ping沒有因為SIGINT信號退出,那么./test.sh不知道子進程ping是由于SIGINT退出的,它認(rèn)為ping是正常退出的,這時./test.sh對SIGINT就會是默認(rèn)不處理,不知道這么理解對不對,要是確實是這樣的話,有鏈接可以共享嗎?
回復(fù) 11# sncchen


   
作者: yjh777    時間: 2015-10-30 15:05
本帖最后由 yjh777 于 2015-10-30 15:07 編輯

我知道原因了,bash的 SIGINT 處理邏輯如下:
    判斷是否還有活著的子進程,如果沒有了就退出,如果還有就忽略;

ping的特殊性在于,它收到信號后,先做一些需要一定時間的操作 然后再退出
    如果這個退出在bash處理SIGINT之前,bash就不會退出。


下面是我寫的一個用于測試的例子,三種情況:
    1) 如果把 sub.sh 里面那個usleep 時間設(shè)置的足夠長,shell就永遠(yuǎn)不會退出
    2) 如果把 usleep 和 上面的echo去掉,快速按幾次Ctr+C 就可以讓shell退出,因為父子進程處理SIGINT的耗時相當(dāng)
    3) 如果sub.sh不去trap SIGINT的話,系統(tǒng)默認(rèn)的SIGINT處理是最快的,
          所以子進程總是在shell處理SIGINT時就死光了,所以shell就一次Ctr+C 就保證退出了
  1. jiyin@dhcp-12-137:~$ cat kkk.sh

  2. while :; do
  3.                 ./sub.sh
  4. done
  5. jiyin@dhcp-12-137:~$ cat sub.sh

  6. sigproc() {
  7.         echo "$@" >>sig.log
  8.         usleep 100000
  9.         exit
  10. }

  11. >sig.log
  12. trap sigproc SIGINT SIGTERM

  13. echo "I am a sub process of kkk.sh $"
  14. sleep 10
復(fù)制代碼
@homerzhou
作者: homerzhou    時間: 2015-11-02 09:38
有道理!回復(fù) 13# yjh777


   
作者: millerix    時間: 2015-11-02 18:18

主要是因為bash 腳本作為父進程處于waitpid時,會檢查子進程是如何退出的。 如果是調(diào)用exit退出的, 父進程不退出,bash 腳本繼續(xù)運行。 如果是因為收到SIGINT信號后做默認(rèn)處理退出的(也就是不捕獲該信號),父進程退出,bash 腳本終止執(zhí)行。

ping代碼中捕獲了SIGINT信號,并安裝了信號處理函數(shù), 該信號處理函數(shù)打印統(tǒng)計信息, 然后正常返回,ping隨后也正常退出了。 bash發(fā)現(xiàn)子進程退出,但是不是因為SIGINT默認(rèn)處理退出的,所以 父進程并不退出, 而是繼續(xù)執(zhí)行。




歡迎光臨 Chinaunix (http://www.72891.cn/) Powered by Discuz! X3.2