1101 Stimmen

Wie kann ich in Bash prüfen, ob eine Zeichenfolge mit einem Wert beginnt?

Ich möchte prüfen, ob eine Zeichenfolge mit "node" beginnt, z. B. "node001". Etwas wie

if [ $HOST == user* ]
  then
  echo yes
fi

Wie kann ich es richtig machen?


Ich muss außerdem Ausdrücke kombinieren, um zu prüfen, ob HOST entweder "user1" ist oder mit "node" beginnt

if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi

> > > -bash: [: too many arguments

Wie kann ich es richtig machen?

1495voto

Mark Rushakoff Punkte 236626

Dieser Ausschnitt aus dem Leitfaden für fortgeschrittene Bash-Skripterstellung dit :

# The == comparison operator behaves differently within a double-brackets
# test than within single brackets.

[[ $a == z* ]]   # True if $a starts with a "z" (wildcard matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

Sie hatten es also fast richtig; Sie brauchten doppelt Klammern, nicht einzelne Klammern.


Was Ihre zweite Frage betrifft, so können Sie sie so formulieren:

HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi

Das Echo wird

yes1
yes2

Bash's if Die Syntax ist gewöhnungsbedürftig (IMO).

356voto

brabster Punkte 41159

Wenn Sie eine neuere Version der Bash (v3+) verwenden, empfehle ich den Bash regex Vergleichsoperator =~ zum Beispiel,

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi

Passend zu this or that in einer Regex, verwenden Sie | zum Beispiel,

if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi

Hinweis: Dies ist die "richtige" Syntax für reguläre Ausdrücke.

  • user* bedeutet use und Null-oder-mehr-Vorkommen von r also use y userrrr wird übereinstimmen.
  • user.* bedeutet user und null oder mehr Vorkommen eines beliebigen Zeichens, also user1 , userX wird übereinstimmen.
  • ^user.* bedeutet Übereinstimmung mit dem Muster user.* am Anfang von $HOST.

Wenn Sie mit der Syntax regulärer Ausdrücke nicht vertraut sind, lesen Sie bitte die diese Ressource .

Beachten Sie, dass die Bash =~ Operator passt nur auf reguläre Ausdrücke, wenn die rechte Seite UNQUOTED . Wenn Sie die rechte Seite in Anführungszeichen setzen, "kann ein beliebiger Teil des Musters in Anführungszeichen gesetzt werden, damit es als Zeichenkette erkannt wird". Sie sollten die rechte Seite nicht in Anführungszeichen setzen, selbst wenn Sie eine Parametererweiterung durchführen.

254voto

Jo So Punkte 22778

Ich versuche immer, bei POSIX zu bleiben. sh statt Bash-Erweiterungen zu verwenden, da einer der wichtigsten Punkte beim Skripting die Portabilität ist (neben Verbindung Programme, nicht deren Ersetzung).

Sur sh gibt es eine einfache Möglichkeit, auf eine "is-prefix"-Bedingung zu prüfen.

case $HOST in node*)
    # Your code here
esac

Wenn man bedenkt, wie alt, geheimnisvoll und verkrustet sh ist (und Bash ist nicht das Heilmittel: Sie ist komplizierter, weniger konsistent und weniger portabel), möchte ich auf einen sehr schönen funktionalen Aspekt hinweisen: Während einige Syntaxelemente wie case eingebaut sind, unterscheiden sich die daraus resultierenden Konstrukte nicht von jedem anderen Auftrag. Sie können auf dieselbe Weise zusammengesetzt werden:

if case $HOST in node*) true;; *) false;; esac; then
    # Your code here
fi

Oder noch kürzer

if case $HOST in node*) ;; *) false;; esac; then
    # Your code here
fi

Oder sogar kürzer (nur zur Vorstellung ! als ein Sprachelement - aber das ist jetzt schlechter Stil)

if ! case $HOST in node*) false;; esac; then
    # Your code here
fi

Wenn Sie gerne explizit sind, bauen Sie Ihr eigenes Sprachelement:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }

Ist das nicht eigentlich ganz nett?

if beginswith node "$HOST"; then
    # Your code here
fi

Und da sh im Grunde nur aus Jobs und String-Listen besteht (und intern aus Prozessen, aus denen Jobs zusammengesetzt sind), können wir jetzt sogar ein wenig funktionale Programmierung betreiben:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }

all() {
    test=$1; shift
    for i in "$@"; do
        $test "$i" || return
    done
}

all "beginswith x" x xy xyz ; checkresult  # Prints TRUE
all "beginswith x" x xy abc ; checkresult  # Prints FALSE

Das ist elegant. Nicht, dass ich es befürworten würde, die sh für irgendetwas Ernstes - es bricht allzu schnell an den Anforderungen der realen Welt (keine Lambdas, also müssen wir Strings verwenden. Aber die Verschachtelung von Funktionsaufrufen mit Strings ist nicht möglich, Pipes sind nicht möglich, usw.)

110voto

martin clayton Punkte 74309

Sie können nur den Teil der Zeichenkette auswählen, den Sie prüfen möchten:

if [ "${HOST:0:4}" = user ]

Für Ihre Folgefrage könnten Sie eine OR :

if [[ "$HOST" == user1 || "$HOST" == node* ]]

65voto

Dennis Williamson Punkte 322329

Ich bevorzuge die anderen Methoden, die bereits gepostet wurden, aber einige Leute verwenden sie gerne:

case "$HOST" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac

Editar:

Ich habe Ihre Alternativen zur obigen Fallbeschreibung hinzugefügt

In Ihrer bearbeiteten Version haben Sie zu viele Klammern. Sie sollte wie folgt aussehen:

if [[ $HOST == user1 || $HOST == node* ]];

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X