Bash: Prüfen, ob ein String einen Teilstring enthält

So prüfst du in Bash zuverlässig, ob ein String einen Teilstring enthält, inklusive sicherem Quoting und typischen Stolperfallen mit Pattern und Regex

Dieser Artikel hat eine Lesedauer von 2 minutes Minuten.

Bash: Prüfen, ob ein String einen Teilstring enthält

Substring-Checks wirken banal, werden in Bash aber schnell unklar, weil Pattern-Matching, Quoting und Regex ähnlich aussehen. Mit zwei, drei sauberen Mustern bekommst du robuste Checks für den Skript-Alltag.

Der pragmatische Standard: Pattern-Matching mit [[]]

Wenn du einfach nur wissen willst, ob ein String einen Teilstring enthält, ist [[ ... ]] mit Wildcards meist die beste Wahl.

text="Hallo Oliver, willkommen im Terminal"
needle="Oliver"

if [[ "$text" == *"$needle"* ]]; then
  echo "Treffer"
else
  echo "Kein Treffer"
fi

Das ist lesbar, schnell und braucht keine externen Tools. Wichtig sind die Anführungszeichen um "$text" und "$needle", damit Leerzeichen nicht zu unerwartetem Verhalten führen.

Was hier wirklich passiert und warum es wichtig ist

In [[ "$text" == *"$needle"* ]] ist *...* Pattern-Matching, kein Regex. Das heißt:

  • * steht für “beliebige Zeichenfolge”
  • das Matching ist shell-intern
  • es ist nicht automatisch “wörtlich”, wenn needle Sonderzeichen enthält

Damit sind wir beim häufigsten Stolperstein.

Stolperstein: Wenn der Teilstring Sonderzeichen enthält

Wenn needle Zeichen wie *, ? oder [ enthält, wird es im Pattern-Kontext besonders. Beispiel: needle="a*b".

Je nach Ziel gibt es zwei sinnvolle Wege:

Weg 1: Du willst Pattern bewusst nutzen

Dann ist das Verhalten sogar nützlich, weil du mit Wildcards flexible Matches bauen kannst.

text="aaab"
if [[ "$text" == a*b ]]; then
  echo "Match"
fi

Weg 2: Du willst literal suchen, ohne Pattern-Effekte

Dann ist case oft die robustere Wahl, weil du die Variable in einer Position hast, in der Bash sie nicht noch einmal als Pattern interpretiert.

text="a*b ist hier wörtlich gemeint"
needle="a*b"

case "$text" in
  *"$needle"*)
    echo "Treffer (literal genug für die Praxis)"
    ;;
  *)
    echo "Kein Treffer"
    ;;
esac

Das löst nicht jedes theoretische Edge-Case, ist aber in vielen Skripten stabiler als ein unbewusstes Pattern-Match mit Sonderzeichen.

Wenn du wirklich garantiert literal matchen musst, führt oft kein Weg an einem Tool vorbei, das Plain-String-Suche explizit anbietet.

Literal und robust: grep -F als Option, wenn Input heikel ist

Wenn die Inputs potenziell “wild” sind, ist grep -F (Fixed String) eine pragmatische Lösung. Du gibst den String per printf rein, um Edge-Cases mit echo zu vermeiden.

text="a*b [test] ?"
needle="a*b"

if printf '%s' "$text" | grep -Fq -- "$needle"; then
  echo "Treffer"
else
  echo "Kein Treffer"
fi

Das ist nicht “reine Bash”, aber sehr verlässlich, wenn du keine Pattern-Interpretation willst.

Regex: Nur wenn du wirklich Muster brauchst

Bash kann Regex mit =~ in [[ ... ]]. Das ist sinnvoll, wenn du nicht nach einem festen Teilstring suchst, sondern nach einem Muster.

text="Order-12345 abgeschlossen"

if [[ "$text" =~ Order-[0-9]+ ]]; then
  echo "Order-ID gefunden"
fi

Warnhinweis: Bei =~ ist das Quoting anders als bei ==. Wenn du die Regex in einer Variable hältst, solltest du vorsichtig sein, weil Quoting das Verhalten verändern kann. Für einfache Substring-Checks ist =~ meist überdimensioniert.

Mini-Skript: Substring-Check als wiederverwendbare Funktion

Dieses Beispiel zeigt zwei Varianten: Pattern-Matching und Fixed-String über grep -F. Du kannst je nach Bedarf entscheiden.

#!/usr/bin/env bash
set -u

contains() {
  local text="$1"
  local needle="$2"

  [[ "$text" == *"$needle"* ]]
}

contains_fixed() {
  local text="$1"
  local needle="$2"

  printf '%s' "$text" | grep -Fq -- "$needle"
}

text="${1:-}"
needle="${2:-}"

if [[ -z "$text" || -z "$needle" ]]; then
  echo "Usage: $0 <text> <needle>" >&2
  exit 1
fi

if contains "$text" "$needle"; then
  echo "Pattern-Check: Treffer"
else
  echo "Pattern-Check: Kein Treffer"
fi

if contains_fixed "$text" "$needle"; then
  echo "Fixed-Check: Treffer"
else
  echo "Fixed-Check: Kein Treffer"
fi

Aufruf:

./contains.sh "a*b [test]" "a*b"

🤫 Pssst: Du möchtest lernen, wie Bash funktioniert? Dann schau dir doch mein Bash-Tutorial für Anfänger an.

Eine Idee im Kopf?


Dann kontaktier mich doch


Wenn du Social-Media-Unterstützung brauchst oder ein Thema journalistisch sauber aufbereiten willst, melde dich.