Escape-Zeichen, die nicht gedruckt werden, in einer Funktion für eine Bash-Eingabeaufforderung

22

In einer Bash-Eingabeaufforderung (PS1-Variable) rufe ich eine Funktion auf, um der Eingabeaufforderung möglicherweise Text hinzuzufügen: export PS1="\u@\h \$(my_function) \$ "

Die Funktion in der Eingabeaufforderung enthält jedoch ANSI-Farbcodes, die sich je nach Ausgabe der Funktion ändern (manchmal rot, manchmal grün). Das Hinzufügen von " \[" zur PS1-Variablen sollte diese Codes als nicht druckbar kennzeichnen, aber wenn ich eine echoFunktion ausführe, wird die " \[" in der Eingabeaufforderung buchstäblich gedruckt.

Wie kann ich diese ANSI-Farbcodes innerhalb einer Funktion für die Verwendung in einer Bash-Eingabeaufforderung umgehen?

MidnightLightning
quelle

Antworten:

34

Die readline- Bibliothek akzeptiert \001und \002(ASCII SOH und STX ) als nicht druckbare Textbegrenzer. Diese funktionieren auch in jeder Anwendung, die readline verwendet .

Von lib/readline/display.c:243im Bash- Quellcode:

243 /* Current implementation:
244         \001 (^A) start non-visible characters
245         \002 (^B) end non-visible characters
246    all characters except \001 and \002 (following a \001) are copied to
247    the returned string; all characters except those between \001 and
248    \002 are assumed to be `visible'. */

Die bash- spezifisch \[und \]werden in der Tat nach \001und \002bei übersetzt y.tab.c:7640.


Hinweis: Wenn Sie bash ‚s printfoder echo -e, und wenn Ihr Text hat \001oder \002unmittelbar vor einer Reihe, werden Sie einen Hit bash Bug, der es um eine Stelle zu viele essen verursacht , wenn Oktal entkommt Verarbeitung - das ist \00142als Oktal interpretiert wird 014 (gefolgt von ASCII "2") anstelle des korrekten Oktals 01 (gefolgt von ASCII "42"). Verwenden Sie aus diesem Grund hexadezimale Versionen \x01und \x02.

Grawity
quelle
Das tut es! echo -e "\001\e[31m\002RED"funktioniert wie erwartet. Vielen Dank!
MidnightLightning
Es tut uns leid, eine Antwort wiederzubeleben, aber was ist das Äquivalent zu dash / ash / sh?
Hosh Sadiq
@Hosh Wenn sie readline benutzen \001und \002funktionieren. Ansonsten bin ich mir nicht sicher. Dash zum Beispiel verwendet Readline definitiv nicht .
wjandrea
1

Hier ist eine schöne vollständige Antwort. Ich musste viel mehr graben, um herauszufinden, wohin die \ 001 usw. mussten. Hoffe das hilft.

# Color prompt for git
reset=$(tput sgr0)
boldgreen=$(tput setaf 2)$(tput bold)
cyan=$(tput sgr0)$(tput setaf 6)
boldred=$(tput setaf 1)$(tput bold)
boldwhite=$(tput setaf 7)$(tput bold)
boldyellow=$(tput setaf 3)$(tput bold)

PARENCLR=$'\001\e[0;36m\002'
BRANCHCLR=$'\001\e[1;33m\002'

alias branchname="git branch 2>/dev/null | grep '*' | sed 's/* \(.*\)/ ${PARENCLR}(${BRANCHCLR}\1${PARENCLR}\)/'"

GIT_STATUS='$(branchname)'

PROMPT_CHAR="\$"
PS1="\[$boldgreen\]\u\[$cyan\]::\[$boldred\]\h \[$cyan\]{\[$boldwhite\].../\W\[$cyan\]}\[$reset\]$GIT_STATUS\[$reset\]$PROMPT_CHAR "

So wie ich es hier eingerichtet habe, werden die Klammern des Git-Zweigs nur angezeigt, wenn Sie sich in einem Git-Zweig befinden, andernfalls ist sie leer.

Dan L
quelle
0

Basierend auf der Antwort von grawity werden im Folgenden ANSI-Steuersequenzen in ASCII SOH( ^A) und STX( ^B) eingeschlossen, die äquivalent zu \[bzw. \]sind:

function readline_ANSI_escape() {
  if [[ $# -ge 1 ]]; then
    echo "$*"
  else
    cat  # Read string from STDIN
  fi | \
  perl -pe 's/(?:(?<!\x1)|(?<!\\\[))(\x1b\[[0-9;]*[mG])(?!\x2|\\\])/\x1\1\x2/g'
}

Verwenden Sie es wie folgt:

$ echo $'\e[0;1;31mRED' | readline_ANSI_escape

Oder:

$ readline_ANSI_escape "$string"

Ein Bonus ist, dass durch mehrmaliges Ausführen der Funktion bereits entflohene Steuercodes nicht wiederhergestellt werden.

Tom Hale
quelle
-2

Wenn Sie sie in der Eingabeaufforderung verwenden möchten, müssen Sie das tun \[. Aber wenn Sie es in einem Echo verwenden möchten, müssen Sie verwenden \033[.

Wuffers
quelle
Hmmm ... Hinzufügen von \ 033 [vor dem ANSI-Befehl ("\ e [31m") und \ 033], nachdem das nächste gedruckte Zeichen in der Eingabeaufforderung nicht gedruckt zu werden scheint.
MidnightLightning
1
Du willst danach nicht mehr \ 033] machen. \ 033 [31m startet die Farbe, danach müssen Sie sie mit \ 033 [0m
Wuffers