Extraire une chaîne, selon un modèle, dans un script bash

17

En bash, supposons que j'ai une chaîne strname:

strname="ph7go04325r"

Je voudrais extraire les caractères entre le premier "3" caractère et le dernier "r" caractère strname, en enregistrant le résultat dans une chaîne strresult. Dans l'exemple ci-dessus, le résultat strresultserait:

strresult="25"

Le premier "3"caractère n'est pas nécessairement à la position de chaîne 8 po strname; de même, la dernière "r"n'est pas nécessairement à la position de chaîne 11. Ainsi, les deux chaînes suivantes strnamedevraient donner strresult="25":

strname="ph11go04325raa"
strname="325r"
strname="rgo04325raa"

Aussi, strname=ph12go04330raa"devrait céder strresult="30".

Je suis nouveau dans le script bash, et je ne sais pas par où commencer pour faire une correspondance de modèle de chaîne comme ceci. Avez-vous des suggestions?

Andrew
la source

Réponses:

28

Vous pouvez utiliser une expression régulière dans bash (3.0 ou supérieur) pour accomplir ceci:

if [[ $strname =~ 3(.+)r ]]; then
    strresult=${BASH_REMATCH[1]}
else
    echo "unable to parse string $strname"
fi

Dans bash, les groupes de capture à partir d'une expression régulière sont placés dans le tableau spécial BASH_REMATCH. L'élément 0 contient la correspondance entière et 1 contient la correspondance du premier groupe de capture.

jordanm
la source
10

Dans la shsyntaxe standard (cela fonctionnerait avec n'importe quelle version de bashou tout autre shell compatible POSIX), vous feriez:

case $strname in
  (*3*r*) 
    strresult=${strname#*3}
    strresult=${strresult%r*};;
  (*)
    printf >&2 '%s\n' "Unable to parse string $strname"
esac

Voir aussi l'ancienne exprsolution qui fonctionnera même sur les Unices de 35 ans:

expr "x$strname" : 'x[^3]*3\(.*\)r'

Le vieux bizarrerie avec exprest que si le match que vous obtenez un statut de sortie non nul (fin) échoue, mais vous obtenez également un statut de sortie non nulle si les chaînes renvoyées à 0 décide (comme avec strname=zz300rzz).

Stéphane Chazelas
la source
Je pense que votre formulation implique à tort que cela ne peut être fait qu'avec les anciennes versions de bash. L'expansion des paramètres est, bien sûr, toujours une bonne approche dans les coques modernes.
kojiro
1
@kojiro, je vois ce que tu veux dire. La formulation initiale devait donner suite à la réponse de la Jordanie. J'ai mis à jour ma réponse.
Stéphane Chazelas