bash $ {VAR // cerca / sostituisci} e strano comportamento regex


8

Sto cercando di fare un po 'di ricerca e sostituzione su una variabile usando l'espansione del parametro $ {VAR // cerca / sostituisci}. Ho una PS1 piuttosto lunga e malvagia, che voglio capire dopo le dimensioni. Per fare ciò devo rimuovere un sacco di sequenze di escape che inserisco. Tuttavia, nel tentativo di rimuovere tutte le sequenze SGR ANSI CSI, ho riscontrato un problema con la mia sintassi.

Data la mia PS1 di:

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ì è malato lo so ...)

Sto provando a fare:

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

Tuttavia, questi sembrano essere avidi al punto di [0-9](quasi come se [0-9]fosse trattato come un .invece):

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

Se rimuovo il *, e cambio [0-9]a [0-9][0-9](dato che è più illustrativo) mi avvicino al risultato atteso:

$ 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$ 

Perché lo *(zero o più) sta facendo cose folli? mi sto perdendo qualcosa qui? Se passo lo stesso regex attraverso sed ottengo il risultato atteso:

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

3
Non è regex, è solo un pattern matching simile a un file glob. extglobinfluenza il comportamento di corrispondenza del modello.
Giordania,

Bum, sarà per questo - ho avuto la sensazione che potesse essere il caso: / Stavo cercando di trovare chiarimenti sul meccanismo di adattamento, senza molto successo. parte per leggere extglob (sembra un lavoro per sed!)
Drav Sloan,

1
*([0-9])è l'equivalente [0-9]*dell'uso extglob.
Giordano,

1
Se hai la risposta corretta, è accettabile rispondere alla tua domanda. Sono stato felice di aver fornito una guida.
Giordano,

2
@DravSloan: questo messaggio è malato! Cool
slm

Risposte:


6

Mi sembra che tu voglia rimuovere le cose tra \[e \]:

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

Tuttavia, la bashsostituzione è così inefficiente che probabilmente sarebbe meglio sparare perlo sedqui, o farlo in un ciclo come:

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

(questa è la sintassi sh POSIX standard sopra, BTW).

E se vuoi il prompt espanso da quello:

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

4
Ah, la mia giornata è completa, un altro gruppo di simboli della maggiore magia degli anziani del Sommo Sacerdote della Command Line, Stephane. Lo giuro per metà dei tuoi post, i miei occhi sono impostati su una velocità di trasmissione errata e ho una schermata di confusione :) E sì, l'obiettivo finale era quello di rimuovere tutte le sequenze di escape: non mi ha colpito semplicemente rimuovere tra [e ]. Grazie!
Drav Sloan,

5

Dopo alcune indicazioni da jordanm (e dalla lettura della sezione "Pattern Matching" della pagina man di bash), si scopre che questi pattern usati dall'espansione dei parametri non sono regex. Tuttavia, per il mio caso specifico, se shopt extglobè attivo, posso fare:

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

dove *([0-9])è uguale [0-9]*a regex.

Sembra che extglob fornisca alcuni meccanismi simili a regex con (dalla pagina man di bash):

          ?(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 sottoinsieme di kshglobs estesi. ksh93in realtà ha un operatore printf per convertire tra pattern e (AT&T) RE ( printf '%P\n' '\\\[[0-9]*\\\]'*\\\[*([0-9])\\\]*)
Stéphane Chazelas,

Hmm, sembra che * [0-9] funzioni in altre query regex (senza parentesi tonde).
macieksk,

0

Supportata l'intera gamma di sequenze ANSI Pure Bash

# 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\{|\}~]/}"
}
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.