在 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例如)。如果出現帶有控制序列的提示,一個副作用是製表位無法正確對齊。

相關內容