Escape de caracteres que no se imprimen en una función para una solicitud Bash

22

En un aviso de Bash (variable PS1), estoy llamando a una función para agregar texto potencialmente a la solicitud: export PS1="\u@\h \$(my_function) \$ "

Sin embargo, la función en el indicador contiene códigos de color ANSI que cambian en función de la salida de la función (a veces roja, a veces verde). Agregar " \[" a la variable PS1 debería escapar de esos códigos como no imprimibles, pero si hago un echoen la función, " \[" se imprime literalmente en el indicador.

¿Cómo puedo escapar de estos códigos de color ANSI desde una función para usar en un indicador de bash?

Medianoche
fuente

Respuestas:

34

La biblioteca readline acepta \001y \002(ASCII SOH y STX ) como delimitadores de texto no imprimibles. Estos también funcionan en cualquier aplicación que use readline .

A partir lib/readline/display.c:243de fiesta de código fuente:

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

Los específicos de bash\[ y \]de hecho se traducen a \001y \002en y.tab.c:7640.


Nota: Si usa bash 's printfo echo -e, y si su texto tiene \001o \002inmediatamente antes de un número, encontrará un error de bash que hace que coma un dígito demasiado cuando procesa escapes octales, es decir, \00142se interpretará como octal 014 (seguido de ASCII "2"), en lugar del octal correcto 01 (seguido de ASCII "42"). Por esta razón, use versiones hexadecimales \x01y en su \x02lugar.

Gravedad
fuente
¡Eso lo hace! echo -e "\001\e[31m\002RED"Funciona como se esperaba. ¡Gracias!
MidnightLightning
Lamento resucitar una respuesta, pero ¿cuál es el equivalente en dash / ash / sh?
Hosh Sadiq
@Hosh Si usan readline, \001y \002funcionará. De lo contrario, no estoy seguro. Dash, por ejemplo, definitivamente no usa readline .
wjandrea
1

Aquí hay una buena respuesta completa. Tuve que investigar mucho más para averiguar a dónde tenía que ir el \ 001, etc. Espero que esto ayude.

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

Tal como lo configuré aquí, los paréntesis de la rama git solo aparecen si estás en una rama git, de lo contrario, está en blanco.

Dan L
fuente
0

Según la respuesta de Grawity , lo siguiente incluirá secuencias de control ANSI en ASCII SOH( ^A) y STX( ^B) que son equivalentes \[y \]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\1\x2/g'
}

Úselo como:

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

O:

$ readline_ANSI_escape "$string"

Como beneficio adicional, ejecutar la función varias veces no volverá a escapar de los códigos de control ya escapados.

Tom Hale
fuente
-2

Si desea usarlos en el indicador, entonces necesita hacer lo \[. Pero si quieres usarlo en un eco, tienes que usarlo \033[.

Wuffers
fuente
Hmmm ... Agregando \ 033 [antes del comando ANSI ("\ e [31m") y \ 033] después de que parece que el siguiente carácter impreso en la solicitud no se imprime.
MidnightLightning
1
No quieres hacer \ 033] después de eso. \ 033 [31m comienza el color, después de eso debes volver a configurarlo con \ 033 [0m
Wuffers