Sfuggire ai caratteri non stampabili in una funzione per un prompt di Bash


22

In un prompt di Bash (variabile PS1), sto chiamando una funzione per aggiungere potenzialmente testo al prompt: export PS1="\u@\h \$(my_function) \$ "

Tuttavia, la funzione nel prompt contiene codici colore ANSI che cambiano in base all'output della funzione (a volte rosso, a volte verde). L'aggiunta di " \[" alla variabile PS1 dovrebbe sfuggire a quei codici come non stampabili, ma se lo faccio echonella funzione, " \[" viene stampato letteralmente nel prompt.

Come posso evitare questi codici colore ANSI all'interno di una funzione per l'uso in un prompt di bash?

Risposte:


34

La libreria readline accetta \001e \002(ASCII SOH e STX ) come delimitatori di testo non stampabili. Funzionano anche in qualsiasi applicazione che utilizza readline .

Da lib/readline/display.c:243nel codice sorgente di bash :

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

I bash -specifici \[e \]sono infatti tradotti in \001e \002in y.tab.c:7640.


Nota: se usi bash 's printfo echo -e, e se il tuo testo ha \001o \002immediatamente prima di un numero, colpirai un bug bash che gli farà mangiare troppe cifre durante l'elaborazione degli escape ottali, cioè \00142sarà interpretato come ottale 014 (seguito da ASCII "2"), anziché dall'ottale 01 corretto (seguito da ASCII "42"). Per questo motivo, utilizzare versioni esadecimali \x01e \x02invece.


Questo lo fa! echo -e "\001\e[31m\002RED"funziona come previsto. Grazie!
MidnightLightning il

Mi dispiace risorgere una risposta, ma qual è l'equivalente su trattino / cenere / sh?
Hosh Sadiq,

@Hosh Se usano readline \001e \002funzioneranno. Altrimenti non ne sono sicuro. Dash, ad esempio, sicuramente non usa readline .
wjandrea,

1

Ecco una bella risposta completa. Ho dovuto fare molto di più per capire dove dovevano andare gli \ 001 ecc. Spero che sia di aiuto.

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

Nel modo in cui l'ho impostato qui, le parentesi del ramo git appaiono solo se sei in un ramo git, altrimenti è vuoto.


0

Sulla base della risposta di Grawity , quanto segue racchiuderà sequenze di controllo ANSI in ASCII SOH( ^A) e STX( ^B) che sono equivalenti \[e \]rispettivamente:

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

Usalo come:

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

O:

$ readline_ANSI_escape "$string"

Come bonus, l'esecuzione della funzione più volte non eviterà nuovamente i codici di controllo già sfuggiti.


-2

Se si desidera utilizzarli nel prompt, è necessario eseguire le operazioni \[. Ma se vuoi usarlo in un'eco, devi usare \033[.


Hmmm ... Aggiungendo \ 033 [prima del comando ANSI ("\ e [31m") e \ 033] dopo sembra che il successivo carattere stampato nel prompt non venga stampato.
MidnightLightning il

1
Non vuoi fare \ 033] dopo. \ 033 [31m avvia il colore, dopodiché è necessario ripristinarlo con \ 033 [0m
Wuffers,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.