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/

4808voto

Adam Bellaire Punkte 103525

Sie können verwenden Marcus' Antwort (* Wildcards) auch außerhalb einer Case-Anweisung, wenn Sie doppelte Klammern verwenden:

string='My long string'
if [[ $string == *"My long"* ]]; then
  echo "It's there!"
fi

Beachten Sie, dass Leerzeichen in der needle-Zeichenkette zwischen Anführungszeichen gesetzt werden müssen, und die * Wildcards sollten draußen sein. Beachten Sie auch, dass ein einfacher Vergleichsoperator verwendet wird (d. h. == ), nicht der Regex-Operator =~ .

192 Stimmen

Beachten Sie auch, dass Sie den Vergleich umkehren können, indem Sie im Test einfach zu != wechseln. Vielen Dank für die Antwort!

5 Stimmen

Hmm, mit genau diesem Code erhalte ich [[: not found . Irgendeine Idee, was falsch ist? Ich verwende GNU bash, Version 4.1.5(1), auf Ubuntu.

81 Stimmen

@Jonik: Vielleicht fehlt Ihnen der ganze Kram oder Sie haben ihn als #!/bin/sh . Versuchen Sie #!/bin/bash stattdessen.

978voto

Matt Tardiff Punkte 8721

Wenn Sie die Regex-Methode bevorzugen:

string='My string';

if [[ $string =~ "My" ]]; then
   echo "It's there!"
fi

3 Stimmen

Musste eine egrep regex in einem Bash-Skript ersetzen, das hat perfekt funktioniert!

122 Stimmen

En =~ Operator sucht bereits in der gesamten Zeichenkette nach einer Übereinstimmung; der .* sind hier überflüssig. Außerdem sind Anführungszeichen im Allgemeinen besser als Backslashes: [[ $string =~ "My s" ]]

27 Stimmen

@bukzor Zitate funktionieren hier seit Bash 3.2+ nicht mehr: tiswww.case.edu/php/chet/bash/FAQ E14) . Es ist wahrscheinlich am besten, einer Variablen zuzuweisen (mit Anführungszeichen) und dann zu vergleichen. Zum Beispiel so: re="My s"; if [[ $string =~ $re ]]

482voto

Marcus Griep Punkte 7748

Ich bin mir bei der Verwendung einer if-Anweisung nicht sicher, aber Sie können einen ähnlichen Effekt mit einer case-Anweisung erzielen:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

106 Stimmen

Dies ist wahrscheinlich die beste Lösung, da sie auf Posix-Shells portabel ist. (a.k.a. keine Bashismen)

40 Stimmen

@technosaurus Ich finde es etwas seltsam, "Bashismus" in einer Frage zu kritisieren, die nur Bash-Tag hat :)

69 Stimmen

@P.P. Es ist nicht so sehr eine Kritik als vielmehr die Bevorzugung einer universelleren Lösung gegenüber einer begrenzteren. Bitte bedenken Sie, dass auch Jahre später noch Leute (wie ich) nach dieser Antwort suchen werden und vielleicht erfreut sind, wenn sie eine Lösung finden, die in einem größeren Rahmen nützlich ist als die ursprüngliche Frage. Wie man in der Open-Source-Welt sagt: "Auswahl ist gut!"

346voto

F. Hauri Punkte 57640

stringContain Varianten (kompatibel oder fallunabhängig)

In diesen Stack Overflow-Antworten wird hauptsächlich über Bash habe ich eine Fall unabhängig Bash-Funktion ganz unten in diesem Beitrag...

Wie auch immer, hier ist mein

Kompatible Antwort

Da es bereits viele Antworten gibt, die Bash-spezifische Funktionen verwenden, gibt es eine Möglichkeit, unter Shells mit weniger Funktionen zu arbeiten, wie BusyBox :

[ -z "${string##*$reqsubstr*}" ]

In der Praxis könnte sich dies ergeben:

string='echo "My string"'
for reqsubstr in 'o "M' 'alt' 'str';do
  if [ -z "${string##*$reqsubstr*}" ] ;then
      echo "String '$string' contain substring: '$reqsubstr'."
    else
      echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
  done

Dies wurde unter Bash getestet, Gedankenstrich , KornShell ( ksh ) und Asche (BusyBox), und das Ergebnis ist immer:

String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.

In einer Funktion

Wie von @EeroAaltonen gewünscht, ist hier eine Version der gleichen Demo, getestet unter den gleichen Shells:

myfunc() {
    reqsubstr="$1"
    shift
    string="$@"
    if [ -z "${string##*$reqsubstr*}" ] ;then
        echo "String '$string' contain substring: '$reqsubstr'.";
      else
        echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
}

Dann:

$ myfunc 'o "M' 'echo "My String"'
String 'echo "My String"' contain substring 'o "M'.

$ myfunc 'alt' 'echo "My String"'
String 'echo "My String"' don't contain substring 'alt'.

Hinweis: müssen Sie Anführungszeichen und/oder doppelte Anführungszeichen auslassen oder doppelt einschließen:

$ myfunc 'o "M' echo "My String"
String 'echo My String' don't contain substring: 'o "M'.

$ myfunc 'o "M' echo \"My String\"
String 'echo "My String"' contain substring: 'o "M'.

Einfache Funktion

Dies wurde unter BusyBox, Dash und natürlich Bash getestet:

stringContain() { [ -z "${2##*$1*}" ]; }

Dann jetzt:

$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi
no
$ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi
yes

... Oder wenn die übermittelte Zeichenkette leer sein könnte, wie von @Sjlver hervorgehoben, würde die Funktion werden:

stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }

oder wie vorgeschlagen von Kommentar von Adrian Günter und vermeidet -o Schalter:

stringContain() { [ -z "${2##$1}" ] && { [ -z "$1" ] || [ -n "$2" ];};}

Letzte (einfache) Funktion:

Und die Umkehrung der Prüfungen, um sie möglicherweise schneller zu machen:

stringContain() { [ -z "$1" ] || { [ -z "${2##*$1*}" ] && [ -n "$2" ];};}

Mit leeren Saiten:

$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

Fallunabhängig (nur Bash!)

Zum Testen von Zeichenketten ohne Berücksichtigung der Groß- und Kleinschreibung konvertieren Sie einfach jede Zeichenkette in Kleinbuchstaben:

stringContain() {
    local _lc=${2,,}
    [ -z "$1" ] || { [ -z "${_lc##*${1,,}*}" ] && [ -n "$2" ] ;} ;}

Prüfen:

stringContain 'o "M3' 'echo "my string"' && echo yes || echo no
no
stringContain 'o "My' 'echo "my string"' && echo yes || echo no
yes
if stringContain '' ''; then echo yes; else echo no; fi
yes
if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

1 Stimmen

Das wäre sogar noch besser, wenn Sie einen Weg finden könnten, das in eine Funktion zu packen.

2 Stimmen

@EeroAaltonen Wie finden Sie meine (neu hinzugefügte) Funktion?

2 Stimmen

Ich weiß! find . -name "*" | xargs grep "myfunc" 2> /dev/null

186voto

Mark Baker Punkte 5408

Sie sollten bedenken, dass es sich bei Shell-Skripten weniger um eine Sprache als vielmehr um eine Sammlung von Befehlen handelt. Instinktiv denken Sie, dass diese "Sprache" von Ihnen verlangt, eine if mit einer [ oder eine [[ . Beides sind nur Befehle, die einen Exit-Status zurückgeben, der Erfolg oder Misserfolg anzeigt (genau wie jeder andere Befehl). Aus diesem Grund würde ich verwenden grep und nicht die [ Befehl.

Tun Sie es einfach:

if grep -q foo <<<"$string"; then
    echo "It's there"
fi

Jetzt, wo Sie daran denken if als Test für den Exit-Status des darauf folgenden Befehls (mit Semikolon) zu verwenden, sollten Sie die Quelle der zu testenden Zeichenfolge überdenken.

## Instead of this
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...

## Simply do this
if file -b "$1" | grep -q "tar archive"; then
#...

El -q bewirkt, dass grep nichts ausgibt, da wir nur den Rückgabewert haben wollen. <<< bewirkt, dass die Shell das nächste Wort expandiert und als Eingabe für den Befehl verwendet, eine einzeilige Version des Befehls << hier dokumentieren (ich bin mir nicht sicher, ob dies ein Standard oder ein Bashismus ist).

9 Stimmen

Werden sie genannt hier Zeichenketten (3.6.7) Ich glaube, es ist Bashismus

13 Stimmen

Kann man auch verwenden Prozess-Substitution if grep -q foo <(echo somefoothing); then

0 Stimmen

Beachten Sie, dass echo ist nicht portabel, wenn Sie eine Variable übergeben, verwenden Sie printf '%s' "$string stattdessen.

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