Comment annuler un test avec des expressions régulières dans un script bash?

174

En utilisant GNU bash (version 4.0.35 (1) -release (x86_64-suse-linux-gnu), je voudrais annuler un test avec des expressions régulières. Par exemple, je voudrais ajouter conditionnellement un chemin à la variable PATH, si le chemin n'est pas déjà là, comme dans:

TEMP=/mnt/silo/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

Je suis sûr qu'il existe un million de façons de le faire, mais ce que j'aimerais savoir, c'est si le conditionnel peut être annulé d'une manière ou d'une autre, comme dans (l'erreur):

TEMP=/mnt/silo/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
export PATH
David Rogers
la source

Réponses:

194

Vous aviez raison, mettez juste un espace entre le !et les [[autresif ! [[

SiegeX
la source
14
Oye vey! Juste au moment où j'évite en toute sécurité la folie des personnages spéciaux intergalactiques de Perl, je me retrouve perdu dans l'espace bash (placement)! (Je sens la peur me serrer les tripes comme un python.) Merci!
David Rogers
127

Vous pouvez également mettre le point d'exclamation entre les crochets:

if [[ ! $PATH =~ $temp ]]

mais vous devez ancrer votre modèle pour réduire les faux positifs:

temp=/mnt/silo/bin
pattern="(^|:)${temp}(:|$)"
if [[ ! "${PATH}" =~ ${pattern} ]]

qui recherche une correspondance au début ou à la fin avec un signe deux-points avant ou après (ou les deux). Je recommande d'utiliser des noms de variables en minuscules ou en casse mixte comme habitude pour réduire le risque de collision de noms avec les variables shell.

Suspendu jusqu'à nouvel ordre.
la source
Ah, merci pour le rappel sur l'ancrage. L'idée d'utiliser des noms de variables minuscules ou mixtes est déroutante pour un débutant bash, car le conseil que j'ai vu jusqu'à présent est d'utiliser des majuscules. Je comprends votre point de vue, mais je n'ai pas vu suffisamment d'exemples de script bash pour me sentir à l'aise de s'écarter de (ma compréhension) du livre de recettes.
David Rogers
4
@anyoneis nous fait confiance sur celui-ci. L'utilisation de variables majuscules définies par l'utilisateur doit être évitée. Toutes les variables de bash sont développées avec $donc il n'y a aucune raison de les mettre en majuscules pour les faire ressortir.
SiegeX
Je trouve if [[ ! $foo =~ bar ]]plus sûr que if ! [[ $foo =~ bar ]], car il est plus facile d'introduire plus de conditions dans leif
CTodea
19

le moyen le plus sûr est de mettre le! pour la négation regex dans le [[ ]]genre:

if [[ ! ${STR} =~ YOUR_REGEX ]]; then

sinon, il pourrait échouer sur certains systèmes.

ça ne vous concerne pas
la source
9

Oui, vous pouvez annuler le test comme SiegeX l' a déjà souligné.

Cependant, vous ne devez pas utiliser d'expressions régulières pour cela - cela peut échouer si votre chemin contient des caractères spéciaux. Essayez plutôt ceci:

[[ ":$PATH:" != *":$1:"* ]]

(La source)

Mark Byers
la source
1
Une autre raison d'utiliser ce formulaire est qu'il ne correspondra pas accidentellement aux sous-chaînes (par exemple, ne pas ajouter "/ bin" au chemin car "/ usr / bin" est déjà là).
Gordon Davisson
Il m'a fallu un certain temps pour comprendre comment les deux points à gauche m'ont donné l'ancrage que je voulais. L'idée de réduire le motif en ajoutant du matériel à la chaîne à rechercher vaut la peine d'être rappelée. Je ne comprends pas pourquoi des caractères spéciaux dans le chemin perturberaient la solution regex mais pas la solution du modèle bash. Peux-tu me donner un exemple?
David Rogers
Je ne pense pas que cela fonctionnera de manière fiable dans tous les cas. Regex correspondant à IMHO supérieur
Felipe Alvarez
5

J'aime simplifier le code sans utiliser d'opérateurs conditionnels dans de tels cas:

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
dimir
la source