如何在不中断行长计算的情况下在 Bash 的 PS1 中包含命令?

l0b*_*0b0 13 bash prompt

Tonin指出了默认提示中的一个错误。最小的例子:

  1. 设置 PS1:

    PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " ")$ '
    
    Run Code Online (Sandbox Code Playgroud)

    此时,提示如下:

    $ 
    
    Run Code Online (Sandbox Code Playgroud)
  2. 现在通过运行触发退出代码输出:

    false
    
    Run Code Online (Sandbox Code Playgroud)

    现在提示在行的开头包含红色的退出代码:

    1 $ 
    
    Run Code Online (Sandbox Code Playgroud)
  3. Ctrl- r
  4. 输入“假”。现在提示只包含搜索:

    (reverse-i-search)`false': false
    
    Run Code Online (Sandbox Code Playgroud)
  5. Enter

生成的终端历史记录现在包含以下内容:

1 $ch)`false': false
Run Code Online (Sandbox Code Playgroud)

预期输出:

1 $ false
Run Code Online (Sandbox Code Playgroud)

也就是说,历史搜索输出似乎与提示混合并隐藏了运行的实际命令。

我尝试使用PROMPT_COMMAND以下方法解决此问题:

set_exit_code() {
    exit_code=$?
    [[ $exit_code -eq 0 ]] || printf %s $(tput setaf 1) $exit_code $(tput sgr0) " "
}
set_bash_prompt() {
    PS1='$(set_exit_code)$ ' # Double quotes give the same result
}
PROMPT_COMMAND=set_bash_prompt
Run Code Online (Sandbox Code Playgroud)

这似乎不起作用 - 搜索和运行后,该行看起来与之前完全相同。

我怎样才能解决这个问题?

Tim*_*tin 9

我在askubuntu.com上找到了答案。@qeirha 提到您必须告诉 bash 字符序列不应计入提示的长度,您可以通过将其包含在\[ \]. 根据提供的示例,这是一种解决方案:

red=$(tput setaf 1)

reset=$(tput sgr0)

[ "$PS1" = "\\s-\\v\\\$ " ] && PS1='$(exit_code=$?; [[ $exit_code -eq 0 ]] || printf %s \[$red\] $exit_code \[$reset\] " ")$ '
Run Code Online (Sandbox Code Playgroud)