152 votes

Correspondance Regex dans une instruction if de Bash

Qu'est-ce que j'ai fait de mal ici ?

J'essaie de faire correspondre toute chaîne de caractères contenant des espaces, des minuscules, des majuscules ou des chiffres. Les caractères spéciaux seraient également appréciés, mais je pense que cela nécessite l'échappement de certains caractères.

TEST="THIS is a TEST title with some numbers 12345 and special char *&^%$#"

if [[ "$TEST" =~ [^a-zA-Z0-9\ ] ]]; then BLAH; fi

Cela ne teste évidemment que les caractères supérieurs, inférieurs, les chiffres et les espaces. Mais cela ne fonctionne pas.

* UPDATE *

Je suppose que j'aurais dû être plus précis. Voici la véritable ligne de code.

if [[ "$TITLE" =~ [^a-zA-Z0-9\ ] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; fi

* UPDATE *

./anm.sh: line 265: syntax error in conditional expression
./anm.sh: line 265: syntax error near `&*#]'
./anm.sh: line 265: `  if [[ ! "$TITLE" =~ [a-zA-Z0-9 $%^\&*#] ]]; then RETURN="FAIL" && ERROR="ERROR: Title can only contain upper and lowercase letters, numbers, and spaces!"; return; fi'

264voto

rici Points 45980

Il y a deux ou trois choses importantes à savoir à propos de la fonction de bash [[ ]] construction. La première :

Le découpage des mots et l'expansion des noms de chemin ne sont pas effectués sur les mots situés entre les balises [[ y ]] ; l'expansion du tilde, l'expansion des paramètres et des variables, l'expansion arithmétique, la substitution de commande, la substitution de processus et la suppression des guillemets sont effectuées.

La deuxième chose :

Un opérateur binaire supplémentaire, '=~', est disponible,... la chaîne à droite de l'opérateur est considérée comme une expression régulière étendue et est appariée en conséquence... N'importe quelle partie du motif peut être citée pour le forcer à correspondre à une chaîne de caractères. .

En conséquence, $v de part et d'autre de la =~ sera étendu à la valeur de cette variable, mais le résultat ne sera pas divisé par des mots ou étendu par des chemins. En d'autres termes, il est parfaitement sûr de laisser les expansions de variables non citées du côté gauche, mais vous devez savoir que les expansions de variables auront lieu du côté droit.

Donc si tu écris : [[ $x =~ [$0-9a-zA-Z] ]] le $0 à l'intérieur de la regex à droite sera développée avant que la regex soit interprétée, ce qui fera probablement échouer la compilation de la regex (à moins que l'expansion de $0 se termine par un chiffre ou un symbole de ponctuation dont la valeur ascii est inférieure à un chiffre). Si vous citez le côté droit comme [[ $x =~ "[$0-9a-zA-Z]" ]] alors le côté droit sera traité comme une chaîne ordinaire, et non comme une regex. (et $0 seront encore élargis). Ce que vous voulez vraiment dans ce cas est [[ $x =~ [\$0-9a-zA-Z] ]]

De même, l'expression entre le [[ y ]] est divisé en mots avant que la regex soit interprétée. Les espaces dans la regex doivent donc être échappés ou cités. Si vous voulez faire correspondre des lettres, des chiffres ou des espaces, vous pouvez utiliser : [[ $x =~ [0-9a-zA-Z\ ] ]] . D'autres caractères doivent également être échappés, par exemple # qui lancerait un commentaire s'il n'était pas cité. Bien entendu, vous pouvez placer le motif dans une variable :

pat="[0-9a-zA-Z ]"
if [[ $x =~ $pat ]]; then ...

Pour les regex qui contiennent beaucoup de caractères qui devraient être échappés ou cités pour passer dans le lexer de bash, beaucoup de gens préfèrent ce style. Mais attention : dans ce cas, vous no puede citer l'expansion de la variable :

# This doesn't work:
if [[ $x =~ "$pat" ]]; then ...

Enfin, je pense que ce que vous essayez de faire est de vérifier que la variable ne contient que des caractères valides. La façon la plus simple d'effectuer cette vérification est de s'assurer qu'elle ne contient pas de caractère non valide. En d'autres termes, une expression comme celle-ci :

valid='0-9a-zA-Z $%&#' # add almost whatever else you want to allow to the list
if [[ ! $x =~ [^$valid] ]]; then ...

! annule le test, en le transformant en un opérateur "ne correspond pas", et l'opérateur [^...] La classe de caractères regex signifie "tout caractère autre que ... ".

La combinaison de l'expansion des paramètres et des opérateurs regex peut rendre la syntaxe des expressions régulières de bash "presque lisible", mais il y a encore quelques problèmes. (N'y en a-t-il pas toujours ?) L'un d'entre eux est que vous ne pouvez pas mettre ] en $valid même si $valid ont été cités, sauf au tout début. (C'est une règle de regex Posix : si vous voulez inclure ] dans une classe de personnage, il doit être placé au début. - peuvent aller au début ou à la fin, donc si vous avez besoin des deux ] y - vous devez commencer par ] et se terminent par - ce qui a conduit à l'émoticône regex "Je sais ce que je fais" : [][-] )

59voto

Oliver Pearmain Points 5096

Au cas où quelqu'un voudrait un exemple utilisant des variables...

#!/bin/bash

# Only continue for 'develop' or 'release/*' branches
BRANCH_REGEX="^(develop$|release//*)"

if [[ $BRANCH =~ $BRANCH_REGEX ]];
then
    echo "BRANCH '$BRANCH' matches BRANCH_REGEX '$BRANCH_REGEX'"
else
    echo "BRANCH '$BRANCH' DOES NOT MATCH BRANCH_REGEX '$BRANCH_REGEX'"
fi

14voto

konsolebox Points 21338

Je préfère utiliser [:punct:] pour ça. Aussi, a-zA-Z09-9 pourrait être juste [:alnum:] :

[[ $TEST =~ ^[[:alnum:][:blank:][:punct:]]+$ ]]

6voto

shonky linux user Points 2524

Ou bien vous êtes en train de répondre à cette question parce que vous avez fait une erreur de frappe comme moi et que vous avez inversé le =~ en ~=.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X