Bash

如何僅殺死目前程序並繼續使用 shell 管道?

  • June 23, 2019

我對 Bash 有兩個相關的疑問。

(Q1)考慮tail -f SomeFile | wc,一個虛構的命令行,其中tail用於模擬一個命令(C1)執行很長時間,不時有一些輸出,並wc用於模擬一個處理該輸出的命令(C2)當 C1 完成時。在等待了很長時間(比平時更長)之後,我想看看到目前為止已經生成了什麼輸出,所以我希望 C1 終止。但是按 Ctrl-C 會殺死整個管道。我怎樣才能只殺死 C1(甚至 C1 的一個組件,如果它本身就是一個複合命令)?

如果 C1 一直在遍歷許多文件並 grep 一些文本,但一個文件來自某個掛起的 nfs 伺服器,那麼我只想殺死那個 grep 程序。

(for F in A B C D E ; do grep sometext $F ; done) | wc

這裡 Ctrl-C 將殺死整個命令行,但我只想殺死目前正在執行(或掛起)的程序並繼續處理剩餘的文件。

我的一個解決方案是打開一個新連接,獲取 ps 輸出,然後“殺死”它。我想知道 Bash 本身是否有解決方案,這樣一些奇怪的組合鍵只會殺死目前程序?

(Q2)在嘗試為這個問題做例子時,我做了這個命令行,在這裡,如果我按 Ctrl-C,我會得到額外的輸出行,如下所示:

# echo `ping 127.0.0.1` | wc
^C

#

當不使用反引號 (``) 時,額外的行不存在:

# tail -f SomeFile | wc
^C
#

我是否認為由於反引號(``)是由 bash 本身處理的,並且當子程序被殺死時,它仍然被認為是“空輸出”,所以它被列印為額外的行?

bash你可以執行:

cmd1 | cmd2 | (trap '' INT; cmd3)

並且 Control-C 只會殺死cmd1and cmd2,但不會殺死cmd3

例子:

$ while sleep .1; do echo -n 1; done | (trap '' INT; tr 1 2)
^C222222222
$ while sleep .1; do echo -n 1; done | tr 1 2
^C

這利用了“忽略”的信號處置被子程序繼承的事實——這trap '' INT也會影響tr命令。但當然,有些命令會安裝自己的SIGINT處理程序,這將打破這個假設。

ksh93不幸的是,由於一個愚蠢的錯誤,這不起作用。一種解決方法可能是:

ksh93$ while sleep .1; do echo -n 1; done | sh -c 'trap "" INT; exec tr 1 2'
^C222222222ksh93$

引用自:https://unix.stackexchange.com/questions/213274