Ucieczka znaków niedrukowalnych w funkcji dla monitu Bash

22

W wierszu polecenia Bash (zmienna PS1) wywołuję funkcję, aby potencjalnie dodać tekst do monitu: export PS1="\u@\h \$(my_function) \$ "

Jednak funkcja w monicie zawiera kody kolorów ANSI, które zmieniają się w zależności od wyniku funkcji (czasami czerwony, czasem zielony). Dodanie „ \[” do zmiennej PS1 powinno uciec od tych kodów jako nie drukujących, ale jeśli wykonam echofunkcję, „ \[” zostanie wydrukowany dosłownie w wierszu polecenia.

Jak mogę uciec od kodów kolorów ANSI z funkcji w celu użycia w zachęcie?

Nocna błyskawica
źródło

Odpowiedzi:

34

Readline biblioteki przyjmuje \001i \002(ASCII SOH i STX ), a nie do druku ograniczników tekstowych. Działają również w dowolnej aplikacji korzystającej z readline .

Od lib/readline/display.c:243w bash kodu źródłowego:

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'. */

Bash -specyficznych \[i \]są w rzeczywistości tłumaczone \001i \002na y.tab.c:7640.


Uwaga: Jeśli używasz bash „s printfczy echo -e, a jeśli tekst ma \001lub \002bezpośrednio przed szereg, to trafisz bash błąd, który powoduje, że jedna cyfra jeść zbyt wiele podczas przetwarzania ósemkowy ucieczki - czyli \00142będzie interpretowany jako ósemkowej 014 (po którym następuje ASCII „2”), zamiast poprawnej ósemki 01 (po której następuje ASCII „42”). Z tego powodu używaj wersji szesnastkowych \x01i \x02zamiast tego.

grawitacja
źródło
To wystarczy! echo -e "\001\e[31m\002RED"działa zgodnie z oczekiwaniami. Dzięki!
MidnightLightning
Przepraszam, że wskrzesiłem odpowiedź, ale jaki jest odpowiednik dash / ash / sh?
Hosh Sadiq,
@Hosh Jeśli używają readline \001i \002będą działać. W przeciwnym razie nie jestem pewien. Dash na przykład zdecydowanie nie używa readline .
wjandrea
1

Oto ładna pełna odpowiedź. Musiałem zrobić o wiele więcej, aby dowiedzieć się, dokąd pójdzie \ 001 itd. Mam nadzieję że to pomoże.

# 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 "

Sposób, w jaki go tu skonfigurowałem, nawiasy gałęzi git pojawiają się tylko wtedy, gdy jesteś w gałęzi git, w przeciwnym razie jest puste.

Dan L.
źródło
0

W oparciu o odpowiedź grawity , następujące sekwencje zawierają sekwencje kontrolne ANSI w ASCII SOH( ^A) i STX( ^B), które są odpowiednio równoważne \[i \]:

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'
}

Używaj go jak:

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

Lub:

$ readline_ANSI_escape "$string"

Jako bonus, wielokrotne uruchomienie tej funkcji nie spowoduje zmiany znaczenia już usuniętych kodów sterujących.

Tom Hale
źródło
-2

Jeśli chcesz ich użyć w wierszu polecenia, musisz wykonać \[. Ale jeśli chcesz użyć go w echu, musisz użyć \033[.

Wuffers
źródło
Hmmm ... Dodanie \ 033 [przed poleceniem ANSI („\ e [31m”) i \ 033] po tym, jak wydaje się, że następny drukowany znak w monicie nie zostanie wydrukowany.
MidnightLightning
1
Po tym nie chcesz robić \ 033]. \ 033 [31m zaczyna kolor, po czym musisz ustawić go z powrotem z \ 033 [0m
Wuffers