我需要防止 SIGINT(Ctrl-C)从子 shell 传播到 Zsh 中的父 shell 函数。
这是一个简单的例子:
function sox-record {
local output="${1:-$(mktemp).wav}"
(
rec "${output}" trim 0 300 # Part of sox package
)
echo "${output}" # Need this to continue executing after Ctrl-C
}
function audio-postprocess {
local audio="$(sox-record)"
# Process the audio file...
echo "${audio}"
}
function audio-transcribe {
local audio="$(audio-postprocess)"
# Send to transcription service...
transcribe_audio "${audio}" # Never reached if Ctrl-C during recording
}
当前的解决方法需要在每个级别捕获 SIGINT,这会导致重复且容易出错的代码:
function sox-record {
local output="${1:-$(mktemp).wav}"
setopt localtraps
trap '' INT
(
rec "${output}" trim 0 300
)
trap - INT
echo "${output}"
}
function audio-postprocess {
setopt localtraps
trap '' INT
local audio="$(sox-record)"
trap - INT
# Process the audio file...
echo "${audio}"
}
function audio-transcribe {
setopt localtraps
trap '' INT
local audio="$(audio-postprocess)"
trap - INT
# Send to transcription service...
transcribe_audio "${audio}"
}
当用户按下 Ctrl-C 停止录制时,我想要:1.rec
子进程终止(工作)2. 父函数继续执行(需要在每个调用者中捕获 SIGINT)
我知道:
- SIGINT 发送给前台进程组中的所有进程
- 使用
setsid
会创建一个新的进程组,但会阻止信号到达子进程 - 添加
trap '' INT
父级需要所有调用者也捕获 SIGINT 以防止传播
有没有办法将 SIGINT 隔离到子 shell,而无需在所有父函数中处理信号?或者,由于 Unix 进程组和信号传播的工作方式,这从根本上是不可能的?
我看了一下这个问题,并尝试这样做:
function sox-record {
local output="${1:-$(mktemp).wav}"
zsh -mfc "rec "${output}" trim 0 300" </dev/null >&2 || true
echo "${output}"
}
当我仅调用 时sox-record
,此方法有效,但当我调用父函数(如 )时audio-postprocess
,Ctrl-C 不会执行任何操作。(而且我必须使用pkill
来杀死rec
。)
function audio-postprocess {
local audio="$(sox-record)"
# Process the audio file...
echo "${audio}"
}