bash $ {VAR // buscar / reemplazar} y comportamiento extraño de expresiones regulares


8

Estoy tratando de buscar y reemplazar una variable usando la expansión del parámetro $ {VAR // buscar / reemplazar}. Tengo una PS1 bastante larga y malvada, que quiero calcular el tamaño de después de la expansión. Para hacerlo, tengo que eliminar un montón de secuencias de escape. Sin embargo, al tratar de eliminar todas las secuencias ANSI CSI SGR, me encontré con un problema con mi sintaxis.

Dada mi PS1 de:

PS1=\[\033]0;[\h] \w\007\]\[\033[1m\]\[\033[37m\](\[\033[m\]\[\033[35m\]\u@\[\033[m
\]\[\033[32m\]\h\[\033[1m\]\[\033[37m\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m
\]\t\[\033[37m\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m\]\[\033[36m\]\w\[\033[1m
\]\[\033[37m\])\[\033[35m\]${git_branch}\[\033[m\]\n$

(sí, está enfermo, lo sé ...)

Estoy tratando de hacer:

# readability
search='\\\[\\033\[[0-9]*m\\\]'
# do the magic
sane="${PS1//$search/}"

Sin embargo, estos parecen ser codiciosos en el punto de [0-9](casi como si [0-9]se tratara como un .lugar):

echo "${PS1//$search/}"
\[\033]0;[\h] \w\007\]\n$ 

Si elimino el *, y cambio [0-9]a [0-9][0-9](ya que es más ilustrativo) me acerco al resultado esperado:

$ search='\\\[\\033\[[0-9][0-9]m\\\]'
$ echo "${PS1//$search/}"
\[\033]0;[\h] \w\007\]\[\033[1m\](\[\033[m\]\u@\[\033[m\]\h\[\033[1m
\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m\]\t\[\033[1m\])\[\033[m\]-\[\033[1m
\](\[\033[m\]\w\[\033[1m\])$(git_branch)\[\033[m\]\n$ 

¿Por qué el *(cero o más) está haciendo locuras? ¿Me estoy perdiendo de algo? Si paso la misma expresión regular a través de sed, obtengo el resultado esperado:

echo $PS1 | sed "s/$search//g"
\[\033]0;[\h] \w\007\](\u@\h)-(\t)-(\w)$(git_branch)\n$

3
No es una expresión regular, es solo una coincidencia de patrones similar a un archivo glob. extglobafecta el comportamiento de coincidencia de patrones.
jordanm

Bum, esa será la razón: tuve el presentimiento de que podría haber sido el caso: / Estaba tratando de encontrar una aclaración del mecanismo de correspondencia, sin mucho éxito. se dirige a leer sobre extglob (¡parece un trabajo para sed!)
Drav Sloan

1
*([0-9])es el equivalente de [0-9]*usar extglob.
jordanm

1
Si obtuvo la respuesta correcta, es aceptable responder su propia pregunta. Estaba feliz de haber brindado alguna orientación.
jordanm

2
@DravSloan: ¡este mensaje está enfermo! 8-)
slm

Respuestas:


6

Me parece que quieres eliminar cosas entre \[y \]:

$ shopt -s extglob
$ printf '%s\n' "${PS1//\\\[*(\\[^]]|[^\\])\\\]/}"
(\u@\h)-(\t)-(\w)${git_branch}\n$

Sin embargo, la bashsustitución es tan ineficiente que probablemente sería mejor disparar perlo sedaquí, o hacerlo en un ciclo como:

p=$PS1 np=
while :; do
  case $p in
    (*\\\[*\\\]*) np=$np${p%%\\\[*};p=${p#*\\\]};;
    (*) break;;
  esac
done
np=$np$p
printf '%s\n' "$np"

(esa es la sintaxis estándar POSIX sh arriba, por cierto).

Y si desea la solicitud expandida de eso:

ep=$(PS4=$np;exec 2>&1;set -x;:); ep=${ep%:}

44
Ah, mi día está completo, otro grupo de símbolos de mayor magia anciana del Sumo Sacerdote de la Línea de Comando, Stephane. Juro por la mitad de tus publicaciones que mis ojos están en la velocidad de transmisión incorrecta y obtengo una pantalla de desorden :) Y sí, el objetivo final era eliminar todas las secuencias de escape: no me llamó la atención simplemente eliminar entre [y ]. ¡Gracias!
Drav Sloan

5

Después de algunas indicaciones de jordanm (y la lectura de la sección "Coincidencia de patrones" de la página del manual de bash), resulta que estos patrones utilizados por la expansión de parámetros no son expresiones regulares. Sin embargo, para mi caso específico, si shopt extglobestá activado, puedo hacer:

search='\\\[\\033\[*([0-9])m\\\]'

donde *([0-9])es lo mismo que [0-9]*en regex.

Parece que extglob proporciona algunos mecanismos similares a regex con (desde bash man page):

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns

2
Sí, extglobimplementa un subconjunto de kshglobos extendidos. ksh93en realidad tiene un operador printf para convertir entre patrones y (AT&T) REs ( printf '%P\n' '\\\[[0-9]*\\\]'da *\\\[*([0-9])\\\]*)
Stéphane Chazelas

Hmm, parece que * [0-9] funciona en otras consultas de expresiones regulares (sin corchetes).
macieksk

0

Pure Bash gama completa de secuencias ANSI compatibles

# Strips ANSI CSI (ECMA-48, ISO 6429) codes from text
# Param:
# 1: The text
# Return:
# &1: The ANSI stripped text
strip_ansi() {
  echo -n "${1//$'\e'[@A-Z\[\\\]\^_]*([0-9:;<=>?])*([ \!\"#$%&\'()\^*+,\-.\/])[@A-Z\[\\\]\^_\`a-z\{|\}~]/}"
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.