3491 Stimmen

Prüfen, ob eine Zeichenkette eine Teilzeichenkette in Bash enthält

Ich habe eine Zeichenfolge in Bash:

string="My string"

Wie kann ich prüfen, ob sie eine andere Zeichenfolge enthält?

if [ $string ?? 'foo' ]; then
  echo "It's there!"
fi

Wo ?? ist mein unbekannter Operator. Verwende ich echo y grep ?

if echo "$string" | grep 'foo'; then
  echo "It's there!"
fi

Das sieht ein bisschen unbeholfen aus.

4 Stimmen

Hallo, wenn leere Zeichenfolgen falsch sind, warum halten Sie es für ungeschickt? Es war der einzige Weg, der für mich funktionierte, trotz der vorgeschlagenen Lösungen.

1 Stimmen

Sie können die expr Befehl hier

9 Stimmen

Hier ist eine für Posix-Shells: stackoverflow.com/questions/2829613/

106voto

ephemient Punkte 189038

Die akzeptierte Antwort ist die beste, aber da es mehr als einen Weg gibt, ist hier eine andere Lösung:

if [ "$string" != "${string/foo/}" ]; then
    echo "It's there!"
fi

${var/search/replace} es $var mit der ersten Instanz von search ersetzt durch replace wenn es gefunden wird (es ändert sich nicht $var ). Wenn Sie versuchen, die foo durch nichts, und die Zeichenkette hat sich geändert, dann offensichtlich foo gefunden wurde.

5 Stimmen

Die obige Lösung von ephemient: > ` if [ "$string" != "${string/foo/}" ]; then echo "Es ist da!" fi` ist nützlich, wenn man die Shell von BusyBox benutzt Asche . Die akzeptierte Lösung funktioniert nicht mit BusyBox, da einige reguläre Ausdrücke der Bash nicht implementiert sind.

3 Stimmen

Die Ungleichheit der Differenz. Ein ziemlich seltsamer Gedanke! Ich liebe ihn

1 Stimmen

Es sei denn, die Zeichenkette ist 'foo'

82voto

Paul Hedderly Punkte 3615

Es gibt also viele nützliche Lösungen für die Frage - aber welche ist am schnellsten / verbraucht die wenigsten Ressourcen?

Wiederholte Tests mit diesem Rahmen:

/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'

TEST wird jedes Mal ausgetauscht:

[[ $b =~ $a ]]           2.92 user 0.06 system 0:02.99 elapsed 99% CPU

[ "${b/$a//}" = "$b" ]   3.16 user 0.07 system 0:03.25 elapsed 99% CPU

[[ $b == *$a* ]]         1.85 user 0.04 system 0:01.90 elapsed 99% CPU

case $b in *$a):;;esac   1.80 user 0.02 system 0:01.83 elapsed 99% CPU

doContain $a $b          4.27 user 0.11 system 0:04.41 elapsed 99%CPU

(doContain war in der Antwort von F. Houri enthalten)

Und zum Schmunzeln:

echo $b|grep -q $a       12.68 user 30.86 system 3:42.40 elapsed 19% CPU !ouch!

Die einfache Substitutionsoption gewinnt also vorhersehbar, ob in einem erweiterten Test oder in einem Fall. Der Fall ist übertragbar.

Ein Piping auf 100000 Greps ist vorhersehbar schmerzhaft! Die alte Regel über die Verwendung externer Hilfsprogramme ohne Notwendigkeit gilt weiterhin.

8 Stimmen

Netter Benchmark. Hat mich davon überzeugt, die [[ $b == *$a* ]] .

2 Stimmen

Wenn ich das richtig lese, case gewinnt mit dem geringsten Gesamtzeitaufwand. Sie vermissen ein Sternchen nach $b in *$a Allerdings. Ich erhalte etwas schnellere Ergebnisse für [[ $b == *$a* ]] als für case wenn der Fehler behoben ist, aber das könnte natürlich auch von anderen Faktoren abhängen.

1 Stimmen

ideone.com/5roEVt hat mein Experiment mit einigen zusätzlichen Fehlern behoben und testet für ein anderes Szenario (wo die Zeichenfolge tatsächlich nicht in der längeren Zeichenfolge vorhanden ist). Die Ergebnisse sind weitgehend ähnlich; [[ $b == *$a* ]] ist schnell und case ist fast genauso schnell (und erfreulicherweise POSIX-kompatibel).

67voto

Mike Q Punkte 5731

Bash 4+ Beispiele. Hinweis: Die Nichtverwendung von Anführungszeichen führt zu Problemen, wenn Wörter Leerzeichen usw. enthalten. In der Bash immer in Anführungszeichen setzen, IMO.

Hier sind einige Beispiele Bash 4+:

Beispiel 1, Prüfung auf 'ja' in der Zeichenkette (Groß- und Kleinschreibung wird nicht berücksichtigt):

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

Beispiel 2, Prüfung auf 'ja' in der Zeichenkette (Groß- und Kleinschreibung wird nicht berücksichtigt):

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

Beispiel 3, Prüfung auf 'ja' in der Zeichenkette (Groß- und Kleinschreibung beachten):

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

Beispiel 4, Prüfung auf 'ja' in der Zeichenkette (Groß- und Kleinschreibung beachten):

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

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

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

Beispiel 6, exakte Übereinstimmung (Groß- und Kleinschreibung unerheblich):

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

Beispiel 7, exakte Übereinstimmung:

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

Beispiel 8, Platzhalterübereinstimmung .ext (Groß- und Kleinschreibung wird nicht berücksichtigt):

     if echo "$a" | egrep -iq "\.(mp[3-4]|txt|css|jpg|png)" ; then

Viel Spaß!

2 Stimmen

Aaaah - ich habe es erst verstanden, nachdem ich herausgefunden habe, dass die beiden Kommas in ${str,,} konvertieren $str zu Kleinbuchstaben. Tolle Lösungen / tolle Liste!

31voto

kevinarpe Punkte 18905

Das funktioniert auch:

if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  printf "Found needle in haystack"
fi

Und der negative Test ist:

if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  echo "Did not find needle in haystack"
fi

Ich nehme an, dass dieser Stil etwas klassischer ist - weniger abhängig von den Funktionen der Bash-Shell.

El -- Argument ist reine POSIX-Paranoia und wird zum Schutz vor Eingabezeichenfolgen verwendet, die Optionen ähneln, wie z. B. --abc o -a .

Hinweis: In einer engen Schleife wird dieser Code viel langsamer als die Verwendung interner Bash-Shell-Funktionen, da ein (oder zwei) separate Prozesse erstellt und über Pipes verbunden werden.

5 Stimmen

...aber der OP sagt nicht, welche Version der Bash; z.B. enthalten ältere Bashs (wie Solaris sie häufig hat) diese neueren Bash-Funktionen möglicherweise nicht. (Ich habe genau dieses Problem (bash pattern matching nicht implementiert) auf Solaris mit bash 2.0)

2 Stimmen

echo nicht portabel ist, sollten Sie die printf '%s' "$haystack stattdessen.

0 Stimmen

@nyuszika7h: Ich war nicht weg echo ist nicht tragbar. Wird /bin/echo arbeiten?

26voto

Samuel Punkte 6806

Als Paul erwähnt in seinem Leistungsvergleich:

if echo "abcdefg" | grep -q "bcdef"; then
    echo "String contains is true."
else
    echo "String contains is not true."
fi

Dies ist POSIX-konform wie der 'case "$string" in'. die von Marcus gegebene Antwort aber sie ist etwas leichter zu lesen als die Antwort auf die Fallbeschreibung. Beachten Sie auch, dass dies sehr viel langsamer ist als die Verwendung einer case-Anweisung. Wie Paul schon sagte, sollten Sie sie nicht in einer Schleife verwenden.

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