Escape caracteres não imprimíveis em uma função para um prompt do Bash

22

Em um prompt do Bash (variável PS1), estou chamando uma função para potencialmente adicionar texto ao prompt: export PS1="\u@\h \$(my_function) \$ "

No entanto, a função no prompt contém códigos de cores ANSI que são alterados com base na saída da função (às vezes vermelho, às vezes verde). Adicionar " \[ " à variável PS1 deve escapar desses códigos como não-imprimíveis, mas se eu fizer um echo na função, o " \[ " será impresso literalmente no prompt.

Como posso escapar desses códigos de cores ANSI de dentro de uma função para uso em um prompt do bash?

    
por MidnightLightning 23.06.2011 / 22:18

4 respostas

34

A biblioteca readline aceita lib/readline/display.c:24321 e \[ (ASCII SOH e STX ) como delimitadores de texto não imprimíveis. Eles também funcionam em qualquer aplicativo que use readline .

De \] no código-fonte bash :

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

As bash -specific y.tab.c:764021 e printf são de fato traduzidas para echo -e e \x0114221 at \x02 .

Observação: se você usar %code% ou %code% de bash , e se o texto tiver %code% ou %code% imediatamente antes de um número, você atingirá um > bash bug que faz com que ele coma um dígito demais ao processar octal escapes - ou seja, %code% será interpretado como octal 014 (seguido por ASCII "2"), em vez do correto octal 01 (seguido por ASCII "42"). Por esse motivo, use as versões hexadecimais %code% e %code% .

    
por 23.06.2011 / 22:28
1

Aqui está uma boa resposta completa. Eu tive que fazer muito mais escavações para descobrir onde o \ 001 etc. tinha que ir. Espero que isso ajude.

# 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=$'
# 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=$'%pre%1\e[0;36m%pre%2'
BRANCHCLR=$'%pre%1\e[1;33m%pre%2'

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

GIT_STATUS='$(branchname)'

PROMPT_CHAR="\$"
PS1="\[$boldgreen\]\u\[$cyan\]::\[$boldred\]\h \[$cyan\]{\[$boldwhite\].../\W\[$cyan\]}\[$reset\]$GIT_STATUS\[$reset\]$PROMPT_CHAR "
1\e[0;36m%pre%2' BRANCHCLR=$'%pre%1\e[1;33m%pre%2' alias branchname="git branch 2>/dev/null | grep '*' | sed 's/* \(.*\)/ ${PARENCLR}(${BRANCHCLR}${PARENCLR}\)/'" GIT_STATUS='$(branchname)' PROMPT_CHAR="\$" PS1="\[$boldgreen\]\u\[$cyan\]::\[$boldred\]\h \[$cyan\]{\[$boldwhite\].../\W\[$cyan\]}\[$reset\]$GIT_STATUS\[$reset\]$PROMPT_CHAR "

Do jeito que eu configurei aqui, os parênteses da ramificação do git só aparecem se você estiver em uma ramificação do git, caso contrário, estará em branco.

    
por 05.02.2016 / 02:47
0

Com base na resposta do grawity , o seguinte incluirá sequências de controle ANSI em ASCII SOH ( ^A ) e STX ( ^B ) que são equivalentes a \[ e \] respectivamente:

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\x2/g'
}

Use como:

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

Ou:

$ readline_ANSI_escape "$string"

Como bônus, a execução da função várias vezes não irá recuperar os códigos de controle já escapados.

    
por 23.09.2018 / 13:52
-2

Se você quiser usá-los no prompt, precisará fazer o \[ . Mas se você quiser usá-lo em um eco, você tem que usar 3[ .

    
por 23.06.2011 / 22:23