Expression régulière dans le script bash

13

Ceci est ma première création de scripts bash, donc je fais probablement une erreur facile.

Fondamentalement, j'essaie d'écrire un script qui obtient les groupes d'un utilisateur, et s'ils se trouvent dans un certain groupe, il enregistrera cela en conséquence. Évidemment, il y aura plus de fonctionnalités, mais cela ne sert à rien de dire que quand je ne peux même pas faire fonctionner l'expression régulière!

Jusqu'à présent, j'ai ceci:

#!/bin/bash

regex="^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"

# example output
groups="username : username usergroup"

echo "$groups" >> /home/jrdn/log

if [[ "$groups" =~ $regex ]]; then
    echo "Match!" >> /home/jrdn/log
else
    echo "No match" >> /home/jrdn/log
fi

Chaque endroit où j'ai essayé ce regex, ça marche. Mais dans le script bash, il ne produit que le $groups, suivi de No match. Alors, quelqu'un peut-il me dire ce qui ne va pas?

jrdn
la source
1
Qu'est-ce qui vous fait penser que quelque chose ne va pas?
manatwork
1
@jrdnhannah puis essayez de recréer lentement votre expression rationnelle cible, premier match ^([a-zA-Z0-9\-_]+)puis ajoutez les deux points et ainsi de suite ... vous devriez découvrir très bientôt, où est le problème.
peterph
2
Même chose ici avec bash 4.2.45. Échapper au trait de soulignement l'a corrigé. Bizarre. @jrdnhannah pourriez-vous écrire cela comme une réponse et l'accepter s'il vous plaît?
terdon
1
Comme je viens de m'inscrire à l'Unix SE, il me faut attendre 8 heures avant de répondre moi-même. Heureux de le marquer comme répondu si quelqu'un d'autre le fait, cependant.
2013
4
@terdon bash appelle probablement les fonctions regex de libc, probablement. Cela dépend donc de la version libc, pas de la version bash. Voir ma réponse ... (Ou peut-être même sur la séquence de classement que vous avez utilisée)
derobert

Réponses:

14

De man 7 regex:

Une expression entre crochets est une liste de caractères entre "[]". …

… Pour inclure un littéral «-», faites-en le premier ou le dernier caractère…. [Tous les autres caractères spéciaux, y compris «\», perdent leur signification spéciale dans une expression entre crochets.

Essayer l'expression rationnelle avec egrep donne une erreur:

$ echo "username : username usergroup" | egrep "^([a-zA-Z0-9\-_]+ : [a-zA-Z0-9\-_]+) (usergroup)$"
egrep: Invalid range end

Voici une version plus simple, qui donne également une erreur:

$ echo 'hi' | egrep '[\-_]'
egrep: Invalid range end

Puisque ce \n'est pas spécial, c'est une gamme, tout comme le [a-z]serait. Vous devez mettre votre -à la fin, comme [_-]ou:

echo "username : username usergroup" | egrep "^([a-zA-Z0-9_-]+ : [a-zA-Z0-9_-]+) (usergroup)$"
username : username usergroup

Cela devrait fonctionner quelle que soit votre version de libc (dans egrep ou bash).

edit: Cela dépend également de vos paramètres régionaux. La page de manuel met en garde à ce sujet:

Les plages sont très dépendantes de la séquence d'assemblage, et les programmes portables devraient éviter de compter sur eux.

Par exemple:

$ echo '\_' | LC_ALL=en_US.UTF8 egrep '[\-_]'
egrep: Invalid range end
$ echo '\_' | LC_ALL=C egrep '[\-_]'
\_

Bien sûr, même s'il n'a pas commis d'erreur, il ne fait pas ce que vous voulez:

$ echo '\^_' | LC_ALL=C egrep '^[\-_]+$'
\^_

Il est une gamme qui en ASCII, comprend \, [, ^et _.

derobert
la source
Intéressant. Mon egrepne donne aucune erreur, il correspond juste correctement.
manatwork
@manatwork votre séquence de classement autorise probablement la plage ....
derobert
Je ne connais pas grand-chose à la collation. Vous voulez dire ceci LC_COLLATE="en_US.UTF-8":?
manatwork
@manatwork J'ai édité la question pour donner un exemple. Notez que cela peut être différent sur votre système, car parfois ces séquences de classement (tri) changent.
derobert
1
@manatwork C'est OK, j'ai presque déposé un rapport de bug avant de remarquer la tentative de fuite -...
derobert
4

Règle générale avec les expressions rationnelles (et tous les bogues dans de plus gros morceaux de code): coupez-le et reconstruisez-le pas à pas ou utilisez la bissection - tout ce qui vous convient le mieux.

Dans ce cas, le coupable s'est avéré être le trait de soulignement - l'échapper avec une barre oblique inversée l'a fait fonctionner.

peterph
la source