為 INT 設置陷阱在子 shell 中不起作用
$ bash -c "trap \"echo INT\" INT; sleep 3" & pid=$!; sleep 1; kill -INT $pid; wait [1] 27811 INT [1]+ Done bash -c "trap \"echo INT\" INT; sleep 3" $ (bash -c "trap \"echo INT\" INT; sleep 3" & pid=$!; sleep 1; kill -INT $pid; wait)
你能解釋一下為什麼
SIGINT
處理程序在第二種情況下沒有被呼叫嗎?
作業控制是指允許使用者在單個登錄會話中在多個程序組(或作業)之間移動的協議。
https://www.gnu.org/software/libc/manual/html_node/Job-Control.html
通常它在互動式 shell 中啟用,在非互動式 shell 中禁用:
$ echo $-; sleep 1 & fg himBHs [1] 84366 sleep 1 $ bash -c 'echo $-; sleep 1 & fg' hBc bash: line 1: fg: no job control
在這種情況下……顯然工作控制被禁用,
$-
不能依賴:$ (echo $-; sleep 1 & fg) himBHs bash: fg: no job control
Shell 將作業與每個管道相關聯。
https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html
也就是說,當啟用作業控制時,每個管道都在單獨的程序組中執行。
pgid.sh
:#!/usr/bin/env bash ps -o pgid= $$
$ ./pgid.sh >&2 | ./pgid.sh >&2; ./pgid.sh; ./pgid.sh & wait 93439 93439 93443 [1] 93445 93445 [1]+ Done ./a.sh $ (./pgid.sh >&2 | ./pgid.sh >&2; ./pgid.sh; ./pgid.sh & wait) 93749 93749 93749 93749
其中一項工作是前台工作,其餘工作是後台工作。
後台作業不應該綁定到啟動它們的 shell。如果您退出 shell,它們將繼續執行。因此,它們不應該被 打斷
SIGINT
,而不是預設情況下。當啟用作業控制時,會自動完成,因為後台作業在單獨的程序組中執行。當作業控制被禁用時,bash
使非同步命令忽略SIGINT
,並且不讓它們(如果它們是bash
腳本)覆蓋它。也就是說,這裡:
$ bash -c "trap 'echo INT' INT; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait
後台作業 (
bash -c "trap 'echo INT' INT; sleep 3"
) 由啟用了作業控制的互動式 shell 執行。結果,後台作業收到SIGINT
.當我們將它包裝到一個沒有作業控制的非互動式 shell 中時:
$ (bash -c "trap 'echo INT' INT; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait)
bash -c "trap 'echo INT' INT; sleep 3"
忽略SIGINT
,trap ... INT
也被忽略。可以這樣確認:
$ bash -c "trap 'echo INT' INT; trap; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait [1] 293631 trap -- 'echo INT' SIGINT trap -- '' SIGFPE INT [1]+ Done bash -c "trap 'echo INT' INT; trap; sleep 3" $ (bash -c "trap 'echo INT' INT; trap; sleep 3" & pid=$!; sleep 1; kill -INT "$pid"; wait) trap -- '' SIGINT trap -- '' SIGQUIT trap -- '' SIGFPE $ bash -c 'ps -o pid,ignored,comm,args -p $$' & wait [1] 345833 PID IGNORED COMMAND COMMAND 345833 0000000000000000 ps ps -o pid,ignored,comm,args -p 345833 [1]+ Done bash -c 'ps -o pid,ignored,comm,args -p $$' $ (bash -c 'ps -o pid,ignored,comm,args -p $$' & wait) PID IGNORED COMMAND COMMAND 345629 0000000000000006 ps ps -o pid,ignored,comm,args -p 345629
一些相關的報價:
由 Bash 啟動的非內置命令將信號處理程序設置為 shell 從其父級繼承的值。**當作業控制無效時,非同步命令會忽略
SIGINT
這些SIGQUIT
**繼承的處理程序。由於命令替換而執行的命令會忽略鍵盤生成的作業控制信號SIGTTIN
、SIGTTOU
和SIGTSTP
。https://www.gnu.org/software/bash/manual/html_node/Signals.html
進入 shell 時忽略的信號不能被擷取或重置。
https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#index-trap
作業控制是指有選擇地停止(暫停)程序的執行並在以後繼續(恢復)它們的執行的能力。使用者通常通過由作業系統核心的終端驅動程序和 Bash 共同提供的互動界面來使用此功能。
Shell 將作業與每個管道相關聯。它保留了一張目前正在執行的作業的表格,該表格可以與
jobs
命令一起列出。當 Bash 非同步啟動一個作業時,它會列印出如下所示的一行:[1] 25647
表示此作業是作業號
1
,並且與此作業關聯的管道中最後一個程序的程序 ID 是25647
. 單個管道中的所有程序都是同一個作業的成員。Bash 使用作業抽像作為作業控制的基礎。為了便於實現作業控制的使用者界面,作業系統維護了目前終端程序組 ID 的概念。此程序組的成員(程序組 ID 等於目前終端程序組 ID 的程序)接收鍵盤生成的信號,例如
SIGINT
. 據說這些過程處於前台。**後台程序是那些程序組 ID 與終端不同的程序;這樣的過程不受鍵盤生成的信號的影響。**只允許前台程序讀取,或者,如果使用者使用 指定stty tostop
,則寫入終端。嘗試從終端讀取(寫入何時stty tostop
生效)的後台程序被發送一個SIGTTIN
(SIGTTOU
) 由核心的終端驅動程序發出的信號,除非被擷取,否則它會暫停程序。https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html