Correspondance de Regex dans une instruction Bash if

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

Essayer de faire correspondre une chaîne contenant des espaces, des minuscules, des majuscules ou des nombres. Les caractères spéciaux seraient bien aussi, mais je pense que cela nécessite d'échapper à 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 nombres supérieurs, inférieurs et les espaces. Ne fonctionne pas bien.

* mise à JOUR *

J'aurais dû être plus précis. Voici la vraie ligne de code réelle.

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

* mise à jour *

./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'
46
demandé sur codeforester 2013-09-10 06:45:53

3 réponses

Il y a quelques choses importantes à savoir sur la construction [[ ]] de bash. Le premier:

Le fractionnement de mots et l'expansion de nom de chemin ne sont pas effectués sur les mots entre [[ et ]]; l'expansion de tilde, l'expansion de paramètre et de variable, l'expansion arithmétique, la substitution de commande, la substitution de processus et la suppression de citation sont effectuées.

La deuxième chose:

Un opérateur binaire supplémentaire‘'=~', est disponible,... la chaîne de le droit de l'opérateur est considéré comme une expression régulière étendue et correspond en conséquence... N'importe quelle partie du motif peut être entre guillemets pour le forcer à correspondre en tant que chaîne.

Par conséquent, $v de chaque côté du {[7] } sera étendu à la valeur de cette variable, mais le résultat ne sera pas word-split ou pathname-expanded. En d'autres termes, il est parfaitement sûr de laisser les expansions de variables non cotées sur le côté gauche, mais vous devez connaître cette variable les expansions se produiront sur le côté droit.

Donc, si vous écrivez: [[ $x =~ [$0-9a-zA-Z] ]], le $0 à l'intérieur de l'expression rationnelle à droite sera développé avant que l'expression rationnelle ne soit interprétée, ce qui entraînera probablement l'échec de la compilation de l'expression rationnelle (sauf si 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-si [[ $x =~ "[$0-9a-zA-Z]" ]], puis le côté droit sera traitée comme une chaîne ordinaire, pas une regex (et $0 sera encore être élargi). Ce que vous voulez vraiment dans ce cas est [[ $x =~ [\$0-9a-zA-Z] ]]

De même, l'expression entre [[ et ]] est divisée en mots avant que l'expression rationnelle ne soit interprétée. Les espaces dans l'expression rationnelle 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, comme #, qui commencerait un commentaire s'il n'était pas cité. Bien sûr, vous pouvez mettre le motif dans une variable:

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

Pour les expressions rationnelles qui contiennent beaucoup de caractères qui devraient être échappés ou cités pour passer par le lexer de bash, beaucoup de gens préfèrent ce style. Mais attention: dans ce cas, vous ne pouvez pas 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 de faire cette vérification est de s'assurer qu'elle ne contient pas de caractère invalide. En d'autres mots, une expression comme ce:

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

! annule le test, le transformant en un opérateur "ne correspond pas", et une 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 d'expression régulière bash "presque lisible", mais il y a encore quelques pièges. (N'est-il pas toujours?) L'un est que vous ne pouviez pas mettre ] dans $valid, même si $valid étaient cités, sauf au tout début. (C'est une règle Posix regex: si vous voulez inclure ] dans une classe de caractères, il doit aller au début. - peut aller au début ou à la fin, donc si vous avez besoin de ] et -, vous devez commencer avec ] et fin avec -, conduisant à l'expression rationnelle "je sais ce que je fais" émoticône: [][-])

107
répondu rici 2018-05-11 16:40:44

Je préférerais utiliser [:punct:] pour cela. En outre, a-zA-Z09-9 pourrait être juste [:alnum:]:

[[ $TEST =~ ^[[:alnum:][:blank:][:punct:]]+$ ]]
10
répondu konsolebox 2013-09-10 04:03:48

Dans le cas où quelqu'un voulait un exemple en 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
7
répondu Oliver Pearmain 2015-01-26 15:16:27