bash $ {VAR // recherche / remplacement} et comportement bizarre de regex

8

J'essaie de faire de la recherche et du remplacement sur une variable en utilisant l'expansion du paramètre $ {VAR // search / replace}. J'ai une PS1 assez longue et maléfique, dont je veux déterminer la taille après l'extension. Pour ce faire, je dois supprimer un tas de séquences d'échappement que je fourre dedans. Cependant, en essayant de supprimer toutes les séquences ANSI CSI SGR, je suis tombé sur un problème avec ma syntaxe.

Compte tenu de ma 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$

(oui c'est malade je sais ...)

J'essaye de faire:

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

Cependant ceux-ci semblent être gourmands au point de [0-9](presque comme [0-9]est traité comme un à la .place):

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

Si je retire le *, et le changement [0-9]à [0-9][0-9](comme cela est plus illustrative) Je me rapproche du résultat attendu:

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

Pourquoi le *(zéro ou plus) fait des choses folles? Est-ce que j'ai râté quelque chose? Si je passe le même regex à travers sed, j'obtiens le résultat attendu:

echo $PS1 | sed "s/$search//g"
\[\033]0;[\h] \w\007\](\u@\h)-(\t)-(\w)$(git_branch)\n$
Drav Sloan
la source
3
Ce n'est pas une expression régulière, c'est juste une correspondance de modèle similaire à un glob de fichier. extglobaffecte le comportement de correspondance de modèle.
jordanm
Bum, ce sera pourquoi - j'ai eu une intuition, cela peut avoir été le cas: / J'essayais de trouver des éclaircissements sur le mécanisme d'appariement, sans grand succès. commence à lire sur extglob (ressemble à un travail pour sed!)
Drav Sloan
1
*([0-9])est l'équivalent de l' [0-9]*utilisation extglob.
jordanm
1
Si vous avez obtenu la bonne réponse, il est acceptable de répondre à votre propre question. J'étais heureux d'avoir fourni quelques conseils.
jordanm
2
@DravSloan - cette invite EST malade! 8-)
slm

Réponses:

6

Pour moi, vous voulez supprimer des choses entre \[et \]:

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

Cependant, la bashsubstitution est si inefficace que vous feriez probablement mieux de tirer perlou sedici, ou de le faire en boucle comme:

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

(c'est la syntaxe standard POSIX sh ci-dessus, BTW).

Et si vous voulez l' invite développée à partir de cela:

ep=$(PS4=$np;exec 2>&1;set -x;:); ep=${ep%:}
Stéphane Chazelas
la source
4
Ah ma journée est terminée, un autre tas de symboles d'une plus grande magie des anciens du grand prêtre de la ligne de commande, Stéphane. Je jure que pour la moitié de vos messages, mes yeux sont réglés sur la mauvaise vitesse de transmission, et je reçois un écran de désordre :) Et oui, le but final était de supprimer toutes les séquences d'échappement: cela ne m'a pas frappé de simplement supprimer entre [et ]. Merci!
Drav Sloan
5

Après quelques conseils de jordanm (et la lecture de la section "Pattern Matching" de la page de manuel bash), il s'avère que ces modèles utilisés par l'expansion des paramètres ne sont pas des expressions rationnelles. Cependant pour mon cas spécifique, s'il shopt extglobest activé, je peux faire:

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

*([0-9])est le même que [0-9]*dans regex.

Il semble que extglob propose des mécanismes similaires à regex avec (à partir de la page de manuel 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
Drav Sloan
la source
2
Oui, extglobimplémente un sous-ensemble de kshglobes étendus. ksh93a en fait un opérateur printf pour convertir entre les motifs et (AT&T) REs ( printf '%P\n' '\\\[[0-9]*\\\]'donne *\\\[*([0-9])\\\]*)
Stéphane Chazelas
Hmm, il semble que * [0-9] fonctionne dans d'autres requêtes d'expression régulière (sans crochets).
macieksk
0

Prise en charge complète de Pure Bash de séquences ANSI

# 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\{|\}~]/}"
}
Léa Gris
la source