So vergleichen Sie Zeichenfolgen in Bash

Antworten:

1375

Verwenden von Variablen in if-Anweisungen

if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

Wenn Sie etwas tun möchten, wenn es nicht übereinstimmt, ersetzen Sie es =durch !=. Weitere Informationen zu Zeichenfolgenoperationen und arithmetischen Operationen finden Sie in der jeweiligen Dokumentation.

Warum verwenden wir Anführungszeichen $x?

Sie möchten die Anführungszeichen verwenden $x, da Ihr Bash-Skript, wenn es leer ist, auf einen Syntaxfehler stößt, wie unten dargestellt:

if [ = "valid" ]; then

Nicht standardmäßige Verwendung des ==Bedieners

Beachten Sie, dass Bash ==für die Gleichstellung mit verwendet werden [kann, dies ist jedoch kein Standard .

Verwenden Sie entweder den ersten Fall, in dem die Anführungszeichen $xoptional sind:

if [[ "$x" == "valid" ]]; then

oder verwenden Sie den zweiten Fall:

if [ "$x" = "valid" ]; then
John Feminella
quelle
12
In welcher Beziehung steht das zu der akzeptierten Antwort in Unerwarteter Bedienerfehler ? Ich habe den gleichen Fehler bei der Verwendung [ "$1" == "on" ]. Durch Ändern von ["$ 1" = "on"] wurde das Problem behoben.
Piotr Dobrogost
78
Die Räume werden benötigt.
TAAPSogeking
6
@ JohnFeminella Wenn Sie in ein Bash-Skript schreiben, sollte es ein einzelnes =und nicht zwei haben.
user13107
73
Es könnte erwähnenswert sein, dass Sie nicht verwenden können [ $x -eq "valid" ]. -eqist der Vergleichsoperator für Ganzzahlen, nicht für Zeichenfolgen.
Craq
2
@Alex, In welchen Fällen (wenn überhaupt) muss ich das Muster verwenden ["x$yes" == "xyes"], bei dem sowohl der Variablen als auch dem Zeichenfolgenliteral ein vorangestellt wird x? Ist das ein Relikt aus alten Zeiten oder wird es in manchen Situationen wirklich gebraucht?
Lanoxx
142

Oder wenn Sie keine else-Klausel benötigen:

[ "$x" == "valid" ] && echo "x has the value 'valid'"
Marko
quelle
71
Und wenn Sie eine else-Klausel benötigen und einen verrückten Einzeiler erstellen möchten: ["$ x" == "valid"] && echo "valid" || Echo "ungültig"
Matt White
11
@ MattWhite: Dies ist normalerweise eine schlechte Idee, da echodies fehlschlagen kann.
gniourf_gniourf
1
Sogar die Fallstricke, die erscheinen könnten, schöne und elegante Wege von Marko
Deko
3
@gniourf_gniourf, kein Problem, verwenden [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
12431234123412341234123
4
@ 12431234123412341234123 { echo invalid && false; }ist effizienter als ( echo invalid && false ), da keine unnötige Subshell bezahlt werden muss.
Charles Duffy
84
a="abc"
b="def"

# Equality Comparison
if [ "$a" == "$b" ]; then
    echo "Strings match"
else
    echo "Strings don't match"
fi

# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
    echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
    echo "$b is lexicographically smaller than $a"
else
    echo "Strings are equal"
fi

Anmerkungen:

  1. Leerzeichen zwischen ifund [und ]sind wichtig
  2. >und <sind Umleitungsoperatoren so entkommen sie mit \>und \<jeweils für Streicher.
Guru
quelle
6
Vielen Dank für den Vergleich der alphabetischen Reihenfolge der Zeichenfolge
Shadi
Mein Problem war, dass es $atatsächlich " "als Teil des String-Literalwerts umgeben war, daher musste ich das Escape-Zeichen verwenden $b, um die Werte zu vergleichen. Ich konnte dies nach dem Ausführen feststellen bash -x ./script.sh. Mit dem Flag -x können Sie den Wert jeder Ausführung anzeigen und beim Debuggen helfen.
ShahNewazKhan
Beachten Sie, dass der alphabetische Reihenfolgevergleich nicht POSIX-standardisiert ist, sodass nicht garantiert werden kann, dass er auf Nicht-GNU-Plattformen / Nicht-Bash-Shells funktioniert. Nur die Vorgänge unter pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html sind garantiert portabel.
Charles Duffy
62

Verwenden Sie zum Vergleichen von Zeichenfolgen mit Platzhaltern

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi
Jeffrey L. Roberts
quelle
12
Es ist wichtig, dass die Platzhalter nur auf der rechten Seite verwendet werden können! Beachten Sie auch die fehlenden "Platzhalter. (Übrigens: +1 für Platzhalter!)
Scz
6
Die Erweiterung $stringB muss angegeben werden (und im Übrigen muss die linke Seite nicht angegeben werden) : if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf
Ich versuche, die gleiche Platzhalterlogik für den Dateinamen im Dateipfad zu verwenden. Aber es funktioniert nicht bei mir. habe alle hier angegebenen Platzhalterzeichenfolgen ausprobiert. aber es geht immer um sonst fall. stringA ist in meinem Fall ein Dateipfad / tmp / file und stringB ist "file".
Regen
35

Ich muss einem der Kommentare in einem Punkt widersprechen:

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Nein, das ist kein verrückter Oneliner

Es sieht nur so aus, als würde man, hmm, den Uneingeweihten ...

In gewisser Weise werden gemeinsame Muster als Sprache verwendet.

Und nachdem du die Sprache gelernt hast.

Eigentlich ist es schön zu lesen

Es ist ein einfacher logischer Ausdruck mit einem besonderen Teil: der verzögerten Auswertung der Logikoperatoren.

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Jeder Teil ist ein logischer Ausdruck; Das erste kann wahr oder falsch sein, die anderen beiden sind immer wahr.

(
[ "$x" == "valid" ] 
&&
echo "valid"
)
||
echo "invalid"

Wenn es nun ausgewertet wird, wird das erste geprüft. Wenn es falsch ist, ist der zweite Operand der Logik und && danach nicht relevant. Das erste ist nicht wahr, also kann es sowieso nicht das erste und das zweite wahr sein.
Nun, in diesem Fall ist die erste Seite der Logik oder || falsch, aber es könnte wahr sein, wenn die andere Seite - der dritte Teil - wahr ist.

Daher wird der dritte Teil bewertet - hauptsächlich das Schreiben der Nachricht als Nebeneffekt. (Es hat das Ergebnis 0für wahr, das wir hier nicht verwenden)

Die anderen Fälle sind ähnlich, aber einfacher - und - das verspreche ich! sind - können - leicht zu lesen sein!
(Ich habe keine, aber ich denke, ein UNIX-Veteran mit grauem Bart zu sein, hilft dabei sehr.)

Volker Siegel
quelle
17
Das ... && ... || ...ist normalerweise verpönt (sorry, Unix-Veteran mit grauem Bart, Sie haben sich die ganze Zeit geirrt), da es semantisch nicht äquivalent zu ist if ... then ... else .... Keine Sorge, dies ist eine häufige Gefahr .
gniourf_gniourf
6
@gniourf_gniourf OP ist nicht falsch - noch sind sie wahrscheinlich unwissend, wie Sie vorschlagen. ... && ... || ...ist ein vollkommen gültiges Muster und eine gängige Bash-Sprache. Die Verwendung setzt Vorkenntnisse voraus (was gut zu beachten ist, wenn Anfänger im Publikum sind), aber OP hat die Haare, um zu beweisen, dass sie wissen, wie man offene Schachtabdeckungen vermeidet.
Ebpa
3
@ebpa Was passiert, wenn die Anweisung nach && den Wert false zurückgibt, wird die Ausführung mit der Anweisung nach || fortgesetzt ? Wenn ja, ist das falsch und vielleicht ist es das, was gniourf vorschlägt
TSG
4
Ich dachte, Echo sei nur ein Beispiel. Die Anweisung nach && gibt möglicherweise immer noch einen Wert ungleich Null zurück
TSG
2
@gniourf_gniourf +1 für das Posten des Links zu Bash Pitfalls! Sehr hilfreich!
Jaguar
21

Sie können auch Use Case / Esac verwenden

case "$string" in
 "$pattern" ) echo "found";;
esac
Ghostdog74
quelle
Ist das Äquivalenz oder enthält?
Ytpillai
@ytpillai, es ist Äquivalenz. Denken Sie daran, dass Sie Muster durch |, vor dem trennen können ). Die inAnweisung entspricht thenin ifAnweisungen. Sie könnten argumentieren, dass es über eine Liste von Mustern funktioniert, wobei jede Liste ihre eigene Erklärung hat, was zu tun ist, wenn Sie aus Python stammen. Nicht wie substring in string, sondern for item in list. Verwenden Sie a *als letzte Anweisung, wenn Sie eine elseBedingung wünschen . Es kehrt bei der ersten Begegnung zurück.
Mazunki
18

Das folgende Skript liest zeilenweise aus einer Datei mit dem Namen "testonthis" und vergleicht dann jede Zeile mit einer einfachen Zeichenfolge, einer Zeichenfolge mit Sonderzeichen und einem regulären Ausdruck. Wenn es nicht übereinstimmt, druckt das Skript die Zeile, andernfalls nicht.

Platz in Bash ist so wichtig. Also wird folgendes funktionieren:

[ "$LINE" != "table_name" ] 

Aber das wird nicht:

["$LINE" != "table_name"] 

Verwenden Sie also bitte unverändert:

cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done
Harshil
quelle
Verwenden Sie diesen Ansatz , um eine Datei zu durchsuchen. Entfernen Sie unter anderem die UUoC.
Fedorqui 'SO hör auf zu schaden'
Es ist nicht wichtig, weil, bashsondern weil [es sich tatsächlich um eine externe Binärdatei handelt (wie in which [ergibt so etwas wie /usr/bin/[)
Patrick Bergner
11

Ich würde wahrscheinlich Regexp-Übereinstimmungen verwenden, wenn die Eingabe nur wenige gültige Einträge enthält. ZB sind nur "Start" und "Stopp" gültige Aktionen.

if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
  echo "valid action"
fi

Beachten Sie, dass ich die Variable $ACTIONmit Doppelkommas in Kleinbuchstaben schreibe. Beachten Sie auch, dass dies bei zu alten Bash-Versionen nicht funktioniert.

steviethecat
quelle
9

Bash 4+ Beispiele. Hinweis: Wenn Sie keine Anführungszeichen verwenden, treten Probleme auf, wenn Wörter Leerzeichen usw. enthalten. Zitieren Sie immer in Bash, IMO.

Hier sind einige Beispiele in Bash 4+:

Beispiel 1: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung wird nicht berücksichtigt):

    if [[ "${str,,}" == *"yes"* ]] ;then

Beispiel 2: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung wird nicht berücksichtigt):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Beispiel 3: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung beachten):

     if [[ "${str}" == *"yes"* ]] ;then

Beispiel 4: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung beachten):

     if [[ "${str}" =~ "yes" ]] ;then

Beispiel 5, genaue Übereinstimmung (Groß- und Kleinschreibung beachten):

     if [[ "${str}" == "yes" ]] ;then

Beispiel 6, genaue Übereinstimmung (ohne Berücksichtigung der Groß- und Kleinschreibung):

     if [[ "${str,,}" == "yes" ]] ;then

Beispiel 7, genaue Übereinstimmung:

     if [ "$a" = "$b" ] ;then

Genießen.

Mike Q.
quelle
Für mich (Mac GNU Bash Version 4.4.12 (1) -release x86_64-apple-darwin17.0.0) muss ich verwenden if [ "$a"="$b" ]oder es funktioniert nicht ... kann keine Leerzeichen um das Gleiche haben
Spektrum
1

Ich habe es auf diese Weise gemacht, die mit Bash und Dash (sh) kompatibel ist :

testOutput="my test"
pattern="my"

case $testOutput in (*"$pattern"*)
    echo "if there is a match"
    exit 1
    ;;
(*)
   ! echo there is no coincidence!
;;esac
Schatten3002
quelle
Was ist der Unterschied zwischen der Verwendung eines Vorgängers und der (Nichtverwendung?
Mazunki