web-dev-qa-db-fra.com

Comment utiliser un regex dans un script shell?

J'essaie de faire correspondre une chaîne avec une expression rationnelle dans un script Shell. Cette chaîne est un paramètre du script ($ 1) et une date (MM/JJ/AAAA). La regex que j'essaie d'utiliser est la suivante:

^\d{2}[\/\-]\d{2}[\/\-]\d{4}$

Cela semble fonctionner, je l'ai essayé sur plusieurs sites de tests de regex.

Mon code Shell est:

REGEX_DATE="^\d{2}[\/\-]\d{2}[\/\-]\d{4}$"
 
echo "$1" | grep -q $REGEX_DATE
echo $?

Le "echo $?" renvoie 1, peu importe la chaîne que je mets en paramètre.

Avez-vous les gars une idée?

Merci !

20
Jérôme G

Je pense que c'est ce que tu veux:

REGEX_DATE='^\d{2}[/-]\d{2}[/-]\d{4}$'

echo "$1" | grep -P -q $REGEX_DATE
echo $?

J'ai utilisé le commutateur -P pour obtenir une expression rationnelle Perl.

13
Chris Lear

Pour compléter les réponses utiles existantes:

Utilisation de du propre opérateur de correspondance des regex de Bash, =~ _ , est une alternative plus rapide dans ce cas, étant donné que vous ne faites correspondre qu’une valeur unique déjà stockée dans une variable:

set -- '12-34-5678' # set $1 to sample value

kREGEX_DATE='^[0-9]{2}[-/][0-9]{2}[-/][0-9]{4}$' # note use of [0-9] to avoid \d
[[ $1 =~ $kREGEX_DATE ]]
echo $? # 0 with the sample value, i.e., a successful match

Notez cependant que l’avertissement concernant l’utilisation de constructions de regex spécifiques à une saveur, telles que \d s'applique également : Alors que =~ prend en charge les ERE ( extended expressions régulières), il prend également en charge l'extension de la plate-forme hôte - il est rare que le comportement de Bash dépende de la plate-forme.

Pour rester portable (dans le contexte de Bash), respectez la spécification POSIX ERE .

Notez que =~ même vous permet de définir des groupes de capture (sous-expressions entre parenthèses) auxquels vous pouvez accéder ultérieurement par le biais de ${BASH_REMATCH[@]} variable de tableau.

Notes complémentaires:

  • $kREGEX_DATE est utilisé non cité, ce qui est nécessaire pour que la regex soit reconnue comme telle (les parties citées seraient traitées comme littéraux).

  • Bien que cela ne soit pas toujours nécessaire, il est conseillé de stocker la regex dans une variable en premier, car Bash a des problèmes avec la regex littéraux contenant \.

    • Par exemple, sous Linux, où \< est pris en charge pour correspondre aux limites du mot, [[ 3 =~ \<3 ]] && echo yes ne fonctionne pas, mais re='\<3'; [[ 3 =~ $re ]] && echo yes Est-ce que.
  • J'ai changé le nom de la variable REGEX_DATE à kREGEX_DATE (k signalant une constante (conceptuelle)), afin de s’assurer que le nom n’est pas un nom tout en majuscule, car les noms de variables en majuscule doivent être évités pour éviter les conflits avec environnement spécial et variables Shell .

44
mklement0

le problème est que vous essayez d'utiliser des fonctionnalités regex non prises en charge par grep. à savoir, votre \d ne fonctionnera pas. utilisez ceci à la place:

REGEX_DATE="^[[:digit:]]{2}[-/][[:digit:]]{2}[-/][[:digit:]]{4}$"
echo "$1" | grep -qE "${REGEX_DATE}"
echo $?

vous avez besoin du -E drapeau pour obtenir ERE afin d'utiliser {#} style.

6
Mike Frysinger