在 PS1 中使用 echo -e 会导致 shell 中出现换行问题

在 PS1 中使用 echo -e 会导致 shell 中出现换行问题

问题

打开命令行提示符:

在此输入图像描述

多次输入字母 a:

在此输入图像描述

输入的文本不是换行到新行,而是换行到同一行:

在此输入图像描述

现在,开始按 b。第二次需要换行时,它将换行到新行:

在此输入图像描述


是什么导致了这种行为?

像这样使用 PS1 会导致以下行为:

ps1Color="\033[1;35m"
export PS1='$(echo -en $ps1Color) Baz $'

请注意,我想使用 echo 而不是直接使用颜色的原因是因为我想根据上一个命令的退出状态有条件地添加颜色

直接使用颜色不会导致出现此行为。


我的问题是:

  • 如何打印用于 PS1 的颜色代码使用回声
  • 如果我想让我的 PS1 有条件地变成不同的颜色,最好的方法是什么?
  • 为什么我会看到这种行为?

更新

需要明确的是,我真的想使用 echo 来做到这一点,因为我想改变颜色有条件的

这就是我现在所拥有的:

function setPs1Colors_start () {

    local previousExit=$?

    local ps1Color="\033[1;35m"
    local ps1FailBackground="\e[41m"

    echo -en $ps1Color

    if [[ previousExit -ne 0 ]]
    then
        echo -en $ps1FailBackground
    fi

}

function setPs1Colors_end () {
    local ps1DefaultColor="\033[0m"
    echo -en $ps1DefaultColor
}

export PS1='$(setPs1Colors_start)[$(date +%b\-%d\ %k:%M)][$(versionControlInfo)\W]\$$(setPs1Colors_end) '

答案1

\033[1;35m是 7 个字符。bash无法猜测这 7 个字符实际上具有空宽度。如果不是,它会认为它们是 7 列宽。

它(或者更确切地说,readline它使用的底层行编辑器)想要知道屏幕上的当前位置,因为当您使用编辑键时,它使用光标定位序列(上、下、左、右)来移动光标。

所以你必须告诉它提示中的哪些字符不会移动光标。对于bash,这是通过使用 it 来完成的\[...\],它告诉 shell 内部的宽度为零。

另请注意,提示扩展 inbash确实会识别\e为 ESC 字符,因此您不必使用echo -e.你可以这样做:

PS1='\[\e[1;35m\] blah $ '

如果你必须使用echo, 或更好的printf, 你会这样做:

PS1='\[$(if ...; then printf "$color1"; fi)\] blah $ '

或者:

PS1='$(if ...; then printf "\[$color1\]"; fi) blah $ '

在 中, 'szsh的等效项与in 类似,但具有更改字符属性的指令,因此您宁愿这样做:bash\[...\]%{...%}tcshzsh

PS1='%B%F{magenta}blah $ '

用于粗体洋红色前景。它还具有某些形式的条件测试,包括 on $?,因此您的redif error, green else 可以写为:

PS1='%F{%(?:green:red%)}blah%f $ '

tcsh%B,但没有%F{color}。所以,你可以使用:

set prompt = '%{\e[1;35m%}blah $ '

ksh88or中pdksh,你会这样做:

PS1=$(printf '\5\r\5\33[1;35m\5blah $ ')

这定义了一个字符(这里是 0x5)逃脱特点。然后,通过在它们之间包含文本,您可以告诉 shell 它不可见。您可以使用 0x5 以外的任何字符,但它不能出现在提示符中,并且除了 mksh 中之外,它必须被终端忽略,因为 shell 实际上会写入它(与 CR 字符一起)。

ksh93仅使用一个光标定位序列:(BS将光标向左移动一列)。要向右移动,它只是重画相同的字符。因此它不需要知道光标位置,只需要知道输入的每个字符的宽度。只要终端在边缘处自动换行,它就可以工作(所以不能正常工作)terminator例如)。如果出现带有控制序列的提示,一个副作用是制表位无法正确对齐。

相关内容