Wie negiere ich einen Test mit regulären Ausdrücken in einem Bash-Skript?

173

Mit GNU bash (Version 4.0.35 (1) -release (x86_64-suse-linux-gnu) möchte ich einen Test mit regulären Ausdrücken negieren. Zum Beispiel möchte ich der PATH-Variablen bedingt einen Pfad hinzufügen. wenn der Pfad noch nicht vorhanden ist, wie in:

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

Ich bin mir sicher, dass es eine Million Möglichkeiten gibt, dies zu tun, aber ich würde gerne wissen, ob die Bedingung irgendwie negiert werden kann, wie in (dem Irrtum):

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
quelle

Antworten:

192

Sie hatten es richtig, setzen Sie einfach ein Leerzeichen zwischen !und [[dergleichenif ! [[

SiegeX
quelle
14
Oye vey! Gerade als ich den intergalaktischen Sondercharakter-Wahnsinn von Perl sicher umgehen kann, finde ich mich im Bash-Raum (Platzierung) verloren! (Ich habe Angst, meinen Bauch wie eine Python zu quetschen.) Danke!
David Rogers
126

Sie können das Ausrufezeichen auch in die Klammern setzen:

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

Sie sollten Ihr Muster jedoch verankern, um Fehlalarme zu reduzieren:

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

die nach einer Übereinstimmung am Anfang oder Ende mit einem Doppelpunkt davor oder danach (oder beiden) sucht. Ich empfehle die Verwendung von Variablennamen in Klein- oder Großbuchstaben, um die Wahrscheinlichkeit von Namenskollisionen mit Shell-Variablen zu verringern.

Bis auf weiteres angehalten.
quelle
Ah, danke für die Erinnerung an die Verankerung. Die Idee, Kleinbuchstaben oder gemischte Variablennamen zu verwenden, ist für einen Bash-Anfänger verwirrend, da der Rat, den ich bisher gesehen habe, darin besteht, Großbuchstaben zu verwenden. Ich verstehe den Punkt, den Sie ansprechen, aber ich habe nicht genug Beispiele für Bash-Skripte gesehen, um mich wohl zu fühlen, wenn ich vom Kochbuch abweiche (mein Verständnis davon).
David Rogers
4
@anyoneis vertrauen uns in diesem Fall. Die Verwendung von benutzerdefinierten Großbuchstaben sollte vermieden werden. Alle Variablen in bash werden mit erweitert, $sodass es keinen Grund gibt, sie in Großbuchstaben zu schreiben, um sie hervorzuheben.
SiegeX
Ich finde es if [[ ! $foo =~ bar ]]sicherer als if ! [[ $foo =~ bar ]], weil es einfacher ist, mehr Bedingungen in dieif
CTodea
19

der sicherste weg ist das zu setzen! für die Regex-Negation innerhalb der folgenden [[ ]]:

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

Andernfalls kann es auf bestimmten Systemen fehlschlagen.

Das geht Sie nichts an
quelle
9

Ja, Sie können den Test negieren, wie SiegeX bereits betont hat.

Sie sollten hierfür jedoch keine regulären Ausdrücke verwenden. Dies kann fehlschlagen, wenn Ihr Pfad Sonderzeichen enthält. Versuchen Sie stattdessen Folgendes:

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

(Quelle)

Mark Byers
quelle
1
Ein weiterer Grund für die Verwendung dieses Formulars ist, dass es nicht versehentlich mit Teilzeichenfolgen übereinstimmt (z. B. kann "/ bin" nicht zum Pfad hinzugefügt werden, da "/ usr / bin" bereits vorhanden ist).
Gordon Davisson
Ich brauchte eine Weile, um zu verstehen, wie die Doppelpunkte links mir die Verankerung gaben, die ich wollte. Die Idee, das Muster durch Hinzufügen von Material zu der zu durchsuchenden Zeichenfolge zu reduzieren, sollte nicht vergessen werden. Ich verstehe nicht, warum Sonderzeichen im Pfad die Regex-Lösung stören würden, aber nicht die Bash-Pattern-Lösung. Kannst du mir ein Beispiel geben?
David Rogers
Ich denke nicht, dass dies in allen Fällen zuverlässig funktionieren wird. Regex Matching im überlegenen IMHO
Felipe Alvarez
5

In solchen Fällen möchte ich den Code vereinfachen, ohne bedingte Operatoren zu verwenden:

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