Bash
如何僅殺死目前程序並繼續使用 shell 管道?
我對 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 只會殺死
cmd1
andcmd2
,但不會殺死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$