У меня есть этот конвейер в моем сценарии оболочки. Он предназначен для того, чтобы предложить пользователю выбрать источники PulseAudio для записи с помощью ffmpeg, но, насколько мне известно, это не имеет значения для этой конкретной проблемы c.
integer num_sources=0
pactl list short sources \
| while IFS= read -r line; do if [[ "$line" =~ '^([[:digit:]]+)\s+(\S+)' ]]; then
echo "#$match[1]: $match[2]"
fi; done \
| (fzf -m --prompt='Select audio source: ' || true) \
| while IFS= read -r src_line; do if [[ "$src_line" =~ '^#([[:digit:]]+)' ]]; then
local pulsesrc="$match[1]"
(( num_sources++ ))
ffpulseopts+=(
-f pulse
-i "$pulsesrc"
)
fi; done
Моя проблема в том, что если я удаляю || true
из вызова fzf, выход из fzf с помощью нажатия Escape, который вызывает ненулевой код выхода, приведет к завершению всего сценария. Я не понимаю, почему это происходит, хотя ни параметры ERR_EXIT
, ни ERR_RETURN
не установлены. PIPE_FAIL
также не задан, хотя я не уверен, как это будет здесь действовать.
λ unsetopt | egrep '^(err|pipe)'
errexit
errreturn
pipefail
Я также проверил эту проблему с более короткими примерами; следующий фрагмент не будет печатать foo
, если вы выйдете из fzf с Escape. Этого не происходит, когда fzf
заменяется на false
, поэтому я смог отследить проблему до кода выхода, который равен 130 (указывает SIGINT) при нажатии Escape.
λ (echo a; echo b; echo c) | fzf | while IFS= read -r line; do echo $line; done; echo foo
λ (echo a; echo b; echo c) | false | while IFS= read -r line; do echo $line; done; echo foo
foo
λ (echo a; echo b; echo c) | (exit 130) | while IFS= read -r line; do echo $line; done; echo foo
Однако, если вы удалите l oop, он будет печататься как положено.
λ (echo a; echo b; echo c) | (exit 130); echo foo
foo
Даже если вы добавите другие детали в конвейер, он все равно будет продолжать печатать foo
правильно
λ (echo a; echo b; echo c) | (exit 130) | false; echo foo
foo
λ (echo a; echo b; echo c) | (exit 130) | true; echo foo
foo
После некоторых недоразумений я обнаружил, что это не только l oop. Это происходит только когда средняя часть трубы выходит с SIGINT
И l oop является последней частью конвейера.
λ (exit 130) | while IFS= read -r line; do echo $line; done; echo foo
foo
λ false | (exit 130) | while IFS= read -r line; do echo $line; done; echo foo
λ true | (exit 130) | while IFS= read -r line; do echo $line; done; echo foo
λ false | (exit 130) | while IFS= read -r line; do echo $line; done | false; echo foo
foo
λ true | (exit 130) | while IFS= read -r line; do echo $line; done | false; echo foo
foo
λ false | (exit 130) | false; echo foo
foo
Я в тупике, и на самом деле не знаю, куда go без взлома, как || true
(|| false
работает так же, как он превращает код выхода SIGINT в "обычный" код выхода ошибки).
Редактировать: По запросу здесь выводится setopt
.
λ setopt
alwaystoend
autocd
autopushd
completeinword
extendedglob
extendedhistory
noflowcontrol
histexpiredupsfirst
histignoredups
histignorespace
histverify
incappendhistory
interactive
interactivecomments
kshglob
longlistjobs
monitor
promptsubst
pushdignoredups
pushdminus
sharehistory
shinstdin
zle
Редактировать 2: Некоторый системный контекст по запросу
Я нахожусь в курсе (по состоянию на 2 мая, 2020, 19:04) Арка Linux, с ZSH 5,8.