web-dev-qa-db-fra.com

Correspondance rationnelle dans une déclaration Bash if

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

Essayer de faire correspondre toute 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 concerne évidemment que les valeurs supérieures, inférieures, les nombres et les espaces. Ça ne marche pas bien.

* UPDATE *

J'imagine que j'aurais dû être plus spécifique. Voici la vraie 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'
56
Atomiklan

Il y a plusieurs choses importantes à savoir sur la construction de [[ ]] de bash. La première:

Le fractionnement des mots et le développement du chemin ne sont pas effectués sur les mots compris entre [[ et ]]; Des extensions tilde, des paramètres et variables, des extensions arithmétiques, des substitutions de commandes, des substitutions de processus et des suppressions de devis sont effectuées.

La deuxième chose:

Un opérateur binaire supplémentaire, '= ~', est disponible, ... la chaîne située à droite de l'opérateur est considérée comme une expression régulière étendue et correspondante en conséquence ... Toute partie du modèle peut être citée pour forcer à faire correspondre à une chaîne.

Par conséquent, $v de part et d'autre du =~ sera étendu à la valeur de cette variable, mais le résultat ne sera pas un fractionnement de Word ou un chemin étendu. En d'autres termes, il est parfaitement sûr de laisser les extensions non citées à gauche, mais vous devez savoir que des extensions variables se produiront à droite.

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

De même, l'expression entre [[ et ]] est scindée en mots avant l'interprétation de la regex. Donc, les espaces dans la regex doivent ê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 ignoré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 regex qui contiennent beaucoup de caractères qu'il faudrait échapper ou citer pour passer à travers le lexer de bash, beaucoup de gens préfèrent ce style. Mais attention: dans ce cas, vous ne pouvez pas citer l'extension 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. Le moyen le plus simple de procéder à cette vérification est de s’assurer qu’il ne contient pas un 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 ...

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

La combinaison des opérateurs de développement de paramètres et de regex peut rendre la syntaxe d'expression régulière bash "presque lisible", mais il y a encore des pièges. (N'est-ce pas toujours le cas?) La première est que vous ne pouviez pas mettre ] dans $valid, même si $valid était cité, sauf au tout début. (C’est une règle regex Posix: si vous voulez inclure ] dans une classe de caractères, il faut y aller au début. - peut aller au début ou à la fin, donc si vous avez besoin des deux ] et -, vous devez commencer par ] et se terminer par -, ce qui conduit à l'expression rationnelle "Je sais ce que je fais": [][-] )

133
rici

Au cas où quelqu'un voudrait 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
13
Oliver Pearmain

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

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