So überprüfen Sie, ob eine Zeichenfolge eine Teilzeichenfolge in Bash enthält

2569

Ich habe eine Zeichenfolge in Bash:

string="My string"

Wie kann ich testen, ob es eine andere Zeichenfolge enthält?

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

Wo ??ist mein unbekannter Betreiber? Benutze ich echo und grep?

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

Das sieht etwas ungeschickt aus.

Davidsheldon
quelle
4
Hallo, wenn leere Zeichenfolgen falsch sind, warum halten Sie es für ungeschickt? Dies war trotz der vorgeschlagenen Lösungen der einzige Weg, der für mich funktioniert hat.
ericson.cepeda
1
Sie können den exprBefehl hier verwenden
cli__
4
Hier ist eine für Posix-Shells: stackoverflow.com/questions/2829613/…
sehe

Antworten:

3652

Sie können die Antwort von Marcus (* Platzhalter) auch außerhalb einer case-Anweisung verwenden, 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 Nadelkette zwischen doppelten Anführungszeichen stehen müssen und die *Platzhalter außerhalb liegen sollten. Beachten Sie auch, dass ein einfacher Vergleichsoperator verwendet wird (dh ==), nicht der Regex-Operator =~.

Adam Bellaire
quelle
127
Beachten Sie auch, dass Sie den Vergleich umkehren können, indem Sie im Test einfach auf! = Wechseln. Danke für die Antwort!
Quinn Taylor
63
@ Jonik: Möglicherweise fehlt Ihnen der Shebang oder Sie haben ihn als #!/bin/sh. Versuchen Sie es #!/bin/bashstattdessen.
Bis auf weiteres angehalten.
10
Lassen Sie zwischen den Klammern und dem Inhalt ein Leerzeichen.
Paul Price
17
Sie müssen keine Variablen in [[]] angeben. Dies wird genauso gut funktionieren: [[$ string == $ Nadel ]] && Echo gefunden
Orwellophile
12
@Orwellophile Vorsicht! Sie können die doppelten Anführungszeichen im ersten Argument nur weglassen [[. Siehe ideone.com/ZSy1gZ
nyuszika7h
611

Wenn Sie den Regex-Ansatz bevorzugen:

string='My string';

if [[ $string =~ "My" ]]
then
   echo "It's there!"
fi
Matt Tardiff
quelle
2
Musste einen egrep Regex in einem Bash-Skript ersetzen, das funktionierte perfekt!
blast_hardcheese
114
Der =~Operator durchsucht bereits die gesamte Zeichenfolge nach einer Übereinstimmung. die .*hier sind irrelevant. Außerdem sind Anführungszeichen Backslashes im Allgemeinen vorzuziehen:[[ $string =~ "My s" ]]
Bukzor
16
@bukzor Quotes funktioniert hier ab Bash 3.2+ nicht mehr: tiswww.case.edu/php/chet/bash/FAQ E14) . Es ist wahrscheinlich am besten, einer Variablen zuzuweisen (in Anführungszeichen) und dann zu vergleichen. So:re="My s"; if [[ $string =~ $re ]]
Seanf
36
Testen Sie, ob es KEINE Zeichenfolge enthält: if [[ ! "abc" =~ "d" ]]ist wahr.
KrisWebDev
1
Beachten Sie, dass die Reihenfolge, in der der Test durchgeführt wird, von Bedeutung ist. Die Ausgabe der folgenden Codezeile wird vorwärts 2 sein.number=2; if [[ "1, 2, 4, 5" = *${number}* ]]; then echo forward $number; fi; if [[ *${number}* = "1, 2, 4, 5" ]]; then echo backwards $number; fi;
Douwe van der Leest
356

Ich bin mir nicht sicher, ob ich eine if-Anweisung verwenden soll, aber Sie können mit einer case-Anweisung einen ähnlichen Effekt erzielen:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac
Marcus Griep
quelle
76
Dies ist wahrscheinlich die beste Lösung, da es für Posix-Shells portabel ist. (aka no bashisms)
Technosaurus
25
@technosaurus Ich finde es ziemlich seltsam, "Bashismus" in einer Frage zu kritisieren, die nur Bash-Tag hat :)
PP
39
@PP Es ist weniger eine Kritik als vielmehr die Bevorzugung einer universelleren Lösung gegenüber einer begrenzteren. Bitte bedenken Sie, dass Jahre später Leute (wie ich) vorbeischauen werden, um nach dieser Antwort zu suchen, und sich möglicherweise freuen, eine zu finden, die in einem größeren Umfang als die ursprüngliche Frage nützlich ist. Wie sie in der Open Source-Welt sagen: "Wahl ist gut!"
Carl Smotricz
2
@technosaurus, FWIW [[ $string == *foo* ]]funktioniert auch in einigen POSIX-kompatiblen sh-Versionen (z. B. /usr/xpg4/bin/shunter Solaris 10) und ksh (> = 88)
maxschlepzig
3
Busybox Ash verarbeitet keine Sternchen in [[... der Gehäuseschalter hat funktioniert!
Ray Foss
232

stringContain Varianten (kompatibel oder fallunabhängig)

Da diese Stack Overflow-Antworten hauptsächlich über Bash berichten , habe ich ganz unten in diesem Beitrag eine fallunabhängige Bash-Funktion veröffentlicht ...

Wie auch immer, da ist meine

Kompatible Antwort

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

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

In der Praxis könnte dies Folgendes 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, Dash , KornShell ( ksh) und ash (BusyBox) getestet 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 eine Funktion

Wie von @EeroAaltonen gefragt, ist hier eine Version derselben Demo, die unter denselben Shells getestet wurde:

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: Sie müssen Anführungszeichen und / oder doppelte Anführungszeichen maskieren 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 Zeichenfolge leer sein könnte, wie von @Sjlver hervorgehoben, würde die Funktion wie folgt lauten:

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

oder wie in Adrian Günters Kommentar vorgeschlagen , um -oSchalter zu vermeiden :

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

Letzte (einfache) Funktion:

Und die Tests umkehren, um sie möglicherweise schneller zu machen:

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

Mit leeren Zeichenfolgen:

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

Groß- und Kleinschreibung unabhängig (nur Bash!)

Um Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung zu testen, konvertieren Sie einfach jede Zeichenfolge 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
F. Hauri
quelle
1
Dies wäre sogar noch besser, wenn Sie herausfinden könnten, wie Sie dies einer Funktion zuordnen können.
Eero Aaltonen
2
@EeroAaltonen Wie findest du meine (neu hinzugefügte) Funktion?
F. Hauri
2
Ich kenne! finden . -name "*" | xargs grep "myfunc" 2> / dev / null
Eiermatratzen
6
Das ist wunderbar, weil es so kompatibel ist. Ein Fehler: Es funktioniert nicht, wenn der Heuhaufen-String leer ist. Die richtige Version wäre string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; } Ein letzter Gedanke: Enthält die leere Zeichenfolge die leere Zeichenfolge? Die obige Version ja (wegen des -o -z "$1"Teils).
Sjlver
3
+1. Sehr gut! Für mich habe ich die Reihenfolge stringContain () {[-z "$ {1 ## * $ 2 *}"] && [-z "$ 2" -o -n "$ 1"] geändert. }; "Suche wo" "Finde was". Arbeiten Sie in der Busybox. Die oben akzeptierte Antwort funktioniert nicht in der Busybox.
user3439968
149

Sie sollten sich daran erinnern, dass Shell-Skripte weniger eine Sprache als eine Sammlung von Befehlen sind. Instinktiv denken Sie, dass diese "Sprache" erfordert, dass Sie einem ifmit einem [oder einem folgen [[. 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 grepund nicht den [Befehl.

Mach einfach:

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

Nachdem Sie nun ifden Exit-Status des darauf folgenden Befehls (einschließlich Semikolon) testen möchten, sollten Sie die Quelle der zu testenden Zeichenfolge erneut überprüfen.

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

Die -qOption bewirkt, dass grep nichts ausgibt, da wir nur den Rückkehrcode wollen. <<<Lässt die Shell das nächste Wort erweitern und es als Eingabe für den Befehl verwenden, eine einzeilige Version des <<hier gezeigten Dokuments (ich bin nicht sicher, ob dies Standard oder ein Bashismus ist).

Mark Baker
quelle
7
sie werden hier Strings genannt (3.6.7) Ich glaube, es ist Bashismus
alex.pilon
10
man kann auch Process Substitution verwenden if grep -q foo <(echo somefoothing); then
larsr
Beachten Sie, dass dies nicht echoportierbar ist. Wenn Sie eine Variable übergeben, verwenden Sie printf '%s' "$stringstattdessen.
Nyuszika7h
5
Die Kosten hierfür sind sehr grep -q foo <<<"$mystring"hoch : implizieren 1 Gabel und ist Bashism und echo $mystring | grep -q fooimplie 2 Gabeln (eine für das Rohr und die zweite für das Laufen /path/to/grep)
F. Hauri
1
@BrunoBronosky echoohne Flags kann immer noch unerwartete Portabilitätsprobleme haben, wenn die Argumentzeichenfolge Backslash-Sequenzen enthält. echo "nope\c"wird erwartet, dass auf einigen Plattformen wie echo -e "nope"auf anderen funktioniert . printf '%s' "nope"vsprintf '%s\n' 'nope\c'
Tripleee
92

Die akzeptierte Antwort ist am besten, 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}wird $varmit der ersten Instanz von searchersetzt durch replace, wenn es gefunden wird (es ändert sich nicht $var). Wenn Sie versuchen, foodurch nichts zu ersetzen , und sich die Zeichenfolge geändert hat, wurde offensichtlich foogefunden.

kurzlebig
quelle
5
Ephemient-Lösung oben:> `if [" $ string "! =" $ {string / foo /} "]; dann Echo "Es ist da!" fi` ist nützlich , wenn BusyBox Shell mit Asche . Die akzeptierte Lösung funktioniert nicht mit BusyBox, da einige reguläre Bash-Ausdrücke nicht implementiert sind.
TPoschel
1
die Ungleichheit der Unterschiede. Ziemlich komischer Gedanke! Ich liebe es
nitinr708
1
es sei denn, Ihre Saite ist 'foo'
venimus
Ich habe dieselbe Lösung selbst geschrieben (weil mein Dolmetscher die besten Antworten nicht annehmen würde) und dann nach einer besseren gesucht, aber diese gefunden!
BuvinJ
56

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 jedes Mal ersetzen:

[[ $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)

Und zum Kichern:

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

Das Auspfeifen auf 100000 Greps ist vorhersehbar schmerzhaft! Die alte Regel über die Verwendung externer Dienstprogramme ohne Notwendigkeit gilt.

Paul Hedderly
quelle
4
Ordentlicher Benchmark. Überzeugte mich zu benutzen [[ $b == *$a* ]].
Verrückter Physiker
2
Wenn ich das richtig lese, casegewinnt mit dem geringsten Gesamtzeitverbrauch. Sie vermissen jedoch ein Sternchen danach $b in *$a. Ich bekomme etwas schnellere Ergebnisse [[ $b == *$a* ]]als casemit dem korrigierten Fehler, aber es könnte natürlich auch von anderen Faktoren abhängen.
Tripleee
1
ideone.com/5roEVt hat mein Experiment mit einigen zusätzlichen Fehlern behoben und Tests für ein anderes Szenario durchgeführt (bei dem die Zeichenfolge in der längeren Zeichenfolge tatsächlich nicht vorhanden ist). Die Ergebnisse sind weitgehend ähnlich. [[ $b == *$a* ]]ist schnell und casefast genauso schnell (und angenehm POSIX-kompatibel).
Tripleee
28

Dies 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, dieser Stil ist etwas klassischer - weniger abhängig von den Merkmalen der Bash-Shell.

Das --Argument ist reine POSIX-Paranoia, die zum Schutz vor Eingabezeichenfolgen verwendet wird, die Optionen wie --abcoder ähneln -a.

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

Kevinarpe
quelle
5
... aber das OP sagt nicht, welche Version von Bash; Beispielsweise enthalten ältere Bashs (wie dies häufig bei Solaris der Fall ist) diese neueren Bash-Funktionen möglicherweise nicht. (Ich bin auf genau dieses Problem
gestoßen
2
echoist nicht portierbar, sollten Sie printf '%s' "$haystackstattdessen verwenden.
Nyuszika7h
2
Nein, vermeiden Sie einfach echoalles andere als wörtlichen Text ohne Escapezeichen, der nicht mit a beginnt -. Es mag für Sie funktionieren, ist aber nicht portabel. Sogar Bashs echoverhalten sich unterschiedlich, je nachdem, ob die xpg_echoOption aktiviert ist. PS: Ich habe vergessen, das doppelte Anführungszeichen in meinem vorherigen Kommentar zu schließen.
Nyuszika7h
1
@kevinarpe Ich bin nicht sicher, --ist nicht in der POSIX-Spezifikation für aufgeführtprintf , aber Sie sollten es printf '%s' "$anything"trotzdem verwenden, um Probleme zu vermeiden, wenn es $anythingein %Zeichen enthält .
Nyuszika7h
1
@kevinarpe Basierend darauf ist es wahrscheinlich.
Nyuszika7h
21

Bash 4+ Beispiele. Hinweis: Wenn Sie keine Anführungszeichen verwenden, treten Probleme auf, wenn Wörter Leerzeichen usw. enthalten. Zitieren Sie immer in Bash, IMO.

Hier sind einige Beispiele für Bash 4+:

Beispiel 1: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung wird nicht berücksichtigt):

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

Beispiel 2: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung wird nicht berücksichtigt):

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

Beispiel 3: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung beachten):

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

Beispiel 4: Überprüfen Sie die Zeichenfolge auf "Ja" (Groß- und Kleinschreibung beachten):

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

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

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

Beispiel 6, genaue Übereinstimmung (ohne Berücksichtigung der Groß- und Kleinschreibung):

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

Beispiel 7, genaue Ü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

Genießen.

Mike Q.
quelle
17

Wie wäre es damit:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi
bn.
quelle
2
= ~ ist für den regulären Ausdruck, daher zu leistungsfähig für den Zweck des OP.
16

Wie Paulus erwähnte 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' der Antwort von Marcus , aber es ist etwas einfacher zu lesen als die Antwort auf die case-Anweisung. Beachten Sie auch, dass dies viel langsamer ist als die Verwendung einer case-Anweisung. Wie Paul betonte, verwenden Sie es nicht in einer Schleife.

Samuel
quelle
11

Diese Stapelüberlauf-Antwort war die einzige, die Leerzeichen abfing und Zeichen strich:

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
Yordan Georgiev
quelle
Es ist eine Antwort auf dieselbe Frage.
Peter Mortensen
9
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
Jahid
quelle
Ich werde hinzufügen, dass die echo "Couldn't findAnweisung am Ende ein guter Trick ist, um 0 Exit-Status für diese übereinstimmenden Befehle zurückzugeben.
Nicodjimenez
@nicodjimenez Mit dieser Lösung können Sie den Exit-Status nicht mehr festlegen. Der Ausgangsstatus wird von den Statusmeldungen verschluckt ...
Jahid
1
Genau das habe ich gemeint ... Wenn Sie keine haben, geben || echo "Couldn't find"Sie einen Fehler-Exit-Status zurück, wenn keine Übereinstimmung vorliegt. Dies möchten Sie möglicherweise nicht, wenn Sie beispielsweise eine CI-Pipeline ausführen, in der alle Befehle zurückgegeben werden sollen Nicht-Fehler-Exit-Status
Nicodjimenez
9

Eines ist:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
chemila
quelle
2
exprist eines dieser Dienstprogramme für Schweizer Taschenmesser, die normalerweise alles tun können, was Sie tun müssen, sobald Sie herausgefunden haben, wie es geht, aber wenn es einmal implementiert ist, können Sie sich nie mehr daran erinnern, warum oder wie es das tut, was es tut, also Sie Berühren Sie es nie wieder und hoffen Sie, dass es nie aufhört zu tun, was es tut.
Michael
@AloisMahdal Ich habe nie abgestimmt, ich postuliere nur, warum Abstimmungen abgegeben wurden. Ein warnender Kommentar. Ich verwende exprin seltenen Fällen, wenn die Portabilität die Verwendung von Bash (z. B. inkonsistentes Verhalten in älteren Versionen), tr (überall inkonsistent) oder sed (manchmal zu langsam) verhindert. Aber aus persönlicher Erfahrung muss exprich , wenn ich diese -ismen noch einmal lese , zur Manpage zurückkehren. Also, ich würde nur kommentieren, dass jede Verwendung von exprkommentiert werden ...
Michael
1
Es gab eine Zeit, in der Sie nur die ursprüngliche Bourne-Muschel hatten. Es fehlten einige häufig erforderliche Funktionen, daher wurden Tools wie exprund testimplementiert, um sie auszuführen. In der heutigen Zeit gibt es normalerweise bessere Werkzeuge, von denen viele in jede moderne Hülle eingebaut sind. Ich denke, es testhängt immer noch drin, aber niemand scheint zu fehlen expr.
Tripleee
6

Ich mag sed.

substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1

Bearbeiten, Logik:

  • Verwenden Sie sed, um die Instanz des Teilstrings aus dem String zu entfernen

  • Wenn sich die neue Zeichenfolge von der alten unterscheidet, ist eine Teilzeichenfolge vorhanden

Reiten
quelle
2
Bitte fügen Sie eine Erklärung hinzu. Die Vermittlung der zugrunde liegenden Logik ist wichtiger als nur die Angabe des Codes, da dies dem OP und anderen Lesern hilft, dieses und ähnliche Probleme selbst zu beheben
Zulan
5

grep -q ist für diesen Zweck nützlich.

Das gleiche mit awk:

string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Ausgabe:

Nicht gefunden

string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Ausgabe:

Gefunden

Ursprüngliche Quelle: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html

nyuszika7h
quelle
3
echoist nicht portierbar, sollten Sie printf '%s' "$string"stattdessen verwenden. Ich bearbeite die Antwort, weil der Benutzer nicht mehr zu existieren scheint.
Nyuszika7h
Inwiefern ist echo@ nyuszika7h nicht portabel?
starbeamrainbowlabs
5

Ich habe festgestellt, dass ich diese Funktionalität ziemlich häufig benötige, daher verwende ich eine hausgemachte Shell-Funktion .bashrcwie diese, mit der ich sie so oft wie nötig wiederverwenden kann, mit einem leicht zu merkenden Namen:

function stringinstring()
{
    case "$2" in
       *"$1"*)
          return 0
       ;;
    esac
    return 1
}

Um zu testen, ob $string1(z. B. abc ) in $string2(z. B. 123abcABC ) enthalten ist , muss ich beispielsweise nur ausführen stringinstring "$string1" "$string2"und nach dem Rückgabewert suchen

stringinstring "$str1" "$str2"  &&  echo YES  ||  echo NO
Kurt Pfeifle
quelle
[["$ str" == $ substr ]] && echo YES || Echo NO
Elyase
Ich bin mir ziemlich sicher, dass der xHack nur für sehr alte Muscheln erforderlich ist .
Nyuszika7h
5

Meine .bash_profile- Datei und wie ich grep verwendet habe:

Wenn die Umgebungsvariable PATH meine beiden binVerzeichnisse enthält, hängen Sie sie nicht an.

# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

U=~/.local.bin:~/bin

if ! echo "$PATH" | grep -q "home"; then
    export PATH=$PATH:${U}
fi
Leslie Satenstein
quelle
1
Ist das eine Antwort?
Codeforester
upvote. Warum sollte man sich die Mühe machen zu lernen, wie Bash es macht, wenn grep, weitaus mächtiger, höchstwahrscheinlich verfügbar sein wird? Erweitern Sie es auch ein wenig weiter, indem Sie es mit einer Liste von Mustern abgleichen : grep -q -E 'pattern1|...|patternN'.
Mohamed Bana
4

Erweiterung der hier beantworteten Frage Wie können Sie feststellen, ob eine Zeichenfolge eine andere Zeichenfolge in POSIX sh enthält? ::

Diese Lösung funktioniert mit Sonderzeichen:

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"

    if echo "$string" | $(type -p ggrep grep | head -1) -F -- "$substring" >/dev/null; then
        return 0    # $substring is in $string
    else
        return 1    # $substring is not in $string
    fi
}

contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"

contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"

contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"
Alex Skrypnyk
quelle
Der Test contains "-n" "n"funktioniert hier nicht, da echo -nder -nals Option geschluckt wird! Eine beliebte Lösung dafür ist die Verwendung printf "%s\n" "$string".
Joeytwiddle
perfekt gelöste Zeichenfolge enthielt Leerzeichen
dengApro
4

Da die POSIX / BusyBox-Frage geschlossen ist, ohne die richtige Antwort zu geben (IMHO), werde ich hier eine Antwort veröffentlichen.

Die kürzest mögliche Antwort lautet:

[ ${_string_##*$_substring_*} ] || echo Substring found!

oder

[ "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Beachten Sie, dass der doppelte Hash bei einigen Shells obligatorisch ist ( ash). Oben wird ausgewertet, [ stringvalue ]wenn der Teilstring nicht gefunden wird. Es wird kein Fehler zurückgegeben. Wenn der Teilstring gefunden wird, ist das Ergebnis leer und wird ausgewertet [ ]. Dies löst den Fehlercode 1 aus, da die Zeichenfolge vollständig ersetzt wird (aufgrund von* ) .

Die kürzeste häufigere Syntax:

[ -z "${_string_##*$_substring_*}" ] && echo 'Substring found!'

oder

[ -n "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Noch einer:

[ "${_string_##$_substring_}" != "$_string_" ] && echo 'Substring found!'

oder

[ "${_string_##$_substring_}" = "$_string_" ] || echo 'Substring found!'

Beachten Sie das einzelne Gleichheitszeichen!

Fünftes Axiom
quelle
3

Genaue Wortübereinstimmung:

string='My long string'
exactSearch='long'

if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
  then
    echo "It's there"
  fi
Eduardo Cuomo
quelle
3

Versuchen Sie es mit Oobash.

Es ist eine String-Bibliothek im OO-Stil für Bash 4. Sie unterstützt deutsche Umlaute. Es ist in Bash geschrieben.

Viele Funktionen stehen zur Verfügung: -base64Decode, -base64Encode, -capitalize, -center, -charAt, -concat, -contains, -count, -endsWith, -equals, -equalsIgnoreCase, -reverse, -hashCode, -indexOf, -isAlnum, -isAlpha, -isAscii, -isDigit, -isEmpty, -isHexDigit, -isLowerCase, -isSpace, -isPrintable, -isUpperCase, -isVisible, -lastIndexOf, -length, -matches, -replaceAll, -replaceFirst, -startsWith, -substring, -swapCase, -toLowerCase, -toString,-toUpperCase , -trim, und -zfill.

Schauen Sie sich das enthält Beispiel:

[Desktop]$ String a testXccc
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false

oobash ist auf Sourceforge.net verfügbar .

andreas
quelle
2

Ich benutze diese Funktion (eine Abhängigkeit nicht enthalten, aber offensichtlich). Es besteht die unten gezeigten Tests. Wenn die Funktion einen Wert> 0 zurückgibt, wurde die Zeichenfolge gefunden. Sie können stattdessen genauso gut 1 oder 0 zurückgeben.

function str_instr {
   # Return position of ```str``` within ```string```.
   # >>> str_instr "str" "string"
   # str: String to search for.
   # string: String to search.
   typeset str string x
   # Behavior here is not the same in bash vs ksh unless we escape special characters.
   str="$(str_escape_special_characters "${1}")"
   string="${2}"
   x="${string%%$str*}"
   if [[ "${x}" != "${string}" ]]; then
      echo "${#x} + 1" | bc -l
   else
      echo 0
   fi
}

function test_str_instr {
   str_instr "(" "'foo@host (dev,web)'" | assert_eq 11
   str_instr ")" "'foo@host (dev,web)'" | assert_eq 19
   str_instr "[" "'foo@host [dev,web]'" | assert_eq 11
   str_instr "]" "'foo@host [dev,web]'" | assert_eq 19
   str_instr "a" "abc" | assert_eq 1
   str_instr "z" "abc" | assert_eq 0
   str_instr "Eggs" "Green Eggs And Ham" | assert_eq 7
   str_instr "a" "" | assert_eq 0
   str_instr "" "" | assert_eq 0
   str_instr " " "Green Eggs" | assert_eq 6
   str_instr " " " Green "  | assert_eq 1
}
Ethan Post
quelle
Die Spannung! Was ist die Abhängigkeit?
Peter Mortensen
Die Funktion "str_escape_special_characters". Es befindet sich in der Datei GitHub arcshell_str.sh. arcshell.io bringt Sie dorthin.
Ethan Post
0
msg="message"

function check {
    echo $msg | egrep [abc] 1> /dev/null

    if [ $? -ne 1 ];
    then 
        echo "found" 
    else 
        echo "not found" 
    fi
}

check

Dies wird jedes Auftreten von a oder b oder c finden

BobMonk
quelle
0

Das generische Nadelheuhaufen- Beispiel folgt mit Variablen

#!/bin/bash

needle="a_needle"
haystack="a_needle another_needle a_third_needle"
if [[ $haystack == *"$needle"* ]]; then
    echo "needle found"
else
    echo "needle NOT found"
fi
Pipo
quelle