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

Antworten:


192

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


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.


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.


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)


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.