^C 导致 PROMPT='$(my_prompt_function)' 永远不会被调用

^C 导致 PROMPT='$(my_prompt_function)' 永远不会被调用

我正在尝试执行一个更复杂的函数,该函数在 ZSH 中构造 PROMPT 字符串,在正常情况下,它可以正常工作。但是,由于我在提示符下发送 SIGINT 时有以下 TRAPINT 来打印“^C”,因此它不起作用(它不调用我的函数)。

.zshrc

TRAPINT() {
    print -n "^C"
    return $(( 128 + $1 ))
}
my_prompt_function() {
    echo '>'
}
setopt PROMPT_SUBST
PROMPT='$(my_prompt_function)'

但是,如果我^C按提示按下,它就会挂起:

>
>^C
# ...hangs here until I press <Enter>

我如何从 TRAPINT 内部判断我是在提示符下,还是在正在运行的程序中,以便不能返回错误?

答案1

看来当 shell 以这种方式中断后,命令替换就不会被评估。

您可以使用钩子来解决这个问题precmd

precmd () {
    MYPROMPT='>'
}
setopt PROMPT_SUBST
PROMPT='${MYPROMPT}'

precmd在每个提示之前运行。请注意,precmd在仅重绘提示而不运行命令行的情况下(如本例),不会重新执行。它仍然有效,因为即使MYPROMPT没有运行, 的值仍然保持不变precmd


  • 您还可以拥有多个precmd函数。您可以使用add-zsh-hook模块来管理它们:

    autoload -Uz add-zsh-hook
    myprompt_function () {
        MYPROMPT='>'
    }
    add-zsh-hook precmd myprompt_function
    setopt PROMPT_SUBST
    PROMPT='${MYPROMPT}'
    
  • 您还可以使用特殊数组变量psvar,其成员可以通过提示转义符来访问%v,或者%Nv其中N要显示的数组索引:

    precmd () {
        psvar[3]='>'
    }
    PROMPT='%3v'
    

答案2

我接受 Adaephon 的回答,但在这里发帖展示我的最终解决方案:

TRAPINT() {
  if [ "$IS_PROMPTING" == true ]; then
    print -n "^C"
    return $(( 128 + $1 ))
  fi
}
precmd() {
  IS_PROMPTING=true
  PROMPT=$(command-that-generates-prompt-string)
}
preexec() {
  IS_PROMPTING=false
}

TRAPINT 有条件地检查用户是否在提示符下或通过 precmd/preexec 适当设置的标志在执行命令内。

相关内容