Preciso evitar que SIGINT (Ctrl-C) se propague de um subshell para suas funções de shell pai no Zsh.
Aqui está um exemplo mínimo:
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
}
A solução alternativa atual requer capturar SIGINT em todos os níveis, o que leva a um código repetitivo e sujeito a erros:
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}"
}
Quando o usuário pressiona Ctrl-C para parar a gravação, eu quero: 1. Que o rec
subprocesso termine (funcionando) 2. Que as funções pai continuem executando (requer captura de SIGINT em cada chamador)
Eu sei que:
- SIGINT é enviado a todos os processos no grupo de processos em primeiro plano
- O uso
setsid
cria um novo grupo de processos, mas impede que os sinais cheguem ao filho - Adicionar
trap '' INT
o pai requer que todos os chamadores também capturem SIGINT para evitar propagação.
Existe uma maneira de isolar SIGINT apenas para o subshell sem exigir tratamento de sinal em todas as funções pai? Ou isso é fundamentalmente impossível devido a como os grupos de processos Unix e a propagação de sinal funcionam?
Dei uma olhada nesta pergunta e tentei isto:
function sox-record {
local output="${1:-$(mktemp).wav}"
zsh -mfc "rec "${output}" trim 0 300" </dev/null >&2 || true
echo "${output}"
}
Embora isso funcione quando eu apenas chamo sox-record
, quando eu chamo uma função pai como audio-postprocess
, Ctrl-C não faz nada. (E eu tenho que usar pkill
to kill rec
.)
function audio-postprocess {
local audio="$(sox-record)"
# Process the audio file...
echo "${audio}"
}