ZSH скрипт завершается, даже если ERR_EXIT выключен - PullRequest
2 голосов
/ 30 апреля 2020

У меня есть этот конвейер в моем сценарии оболочки. Он предназначен для того, чтобы предложить пользователю выбрать источники 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.

...