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.

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
needleSonderzeichen 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.


