it-swarm.com.de

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

Ich habe eine Zeichenfolge in Bash:

string="My string"

Wie kann ich testen, ob eine andere Zeichenfolge enthalten ist?

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

Wo ?? mein unbekannter Operator ist. Benutze ich echo und grep?

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

Das sieht etwas unbeholfen aus.

1969
davidsheldon

Sie können auch Marcus 'Antwort (* Wildcards) 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 Anführungszeichen gesetzt werden müssen und die *-Platzhalterzeichen außerhalb liegen müssen.

2842
Adam Bellaire

Wenn Sie den Regex-Ansatz bevorzugen:

string='My string';

if [[ $string =~ .*My.* ]]
then
   echo "It's there!"
fi
429
Matt Tardiff

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

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

Kompatible Antwort

Da es bereits viele Antworten mit Bash-spezifischen Funktionen gibt, gibt es eine Möglichkeit, unter ärmeren Shells zu arbeiten, wie busybox :

[ -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 , ksh und ash (busybox) getestet. 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 gefragt, ist hier eine Version derselben Demo, die unter den gleichen Shells getestet wurde:

myfunc() {
    reqsubstr="$1"
    shift
    string="[email protected]"
    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 setzen oder 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*}" ]; }

Das war's Leute!

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 übergebene Zeichenfolge leer sein könnte, wie von @Sjlver gezeigt, würde die Funktion zu:

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

oder wie von Adrian Günters Kommentar vorgeschlagen , -o-Umschaltung vermeiden:

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

Mit leeren Zeichenketten: 

$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
172
F. Hauri

Sie sollten sich daran erinnern, dass Shell-Scripting weniger eine Sprache als eine Sammlung von Befehlen ist. Instinktiv denken Sie, dass diese "Sprache" verlangt, dass Sie einer if mit einem [ oder einem [[ folgen. Bei beiden Befehlen handelt es sich lediglich um Befehle, die einen Exit-Status zurückgeben, der auf Erfolg oder Misserfolg hinweist (wie bei jedem anderen Befehl). Aus diesem Grund würde ich grep verwenden und nicht den [-Befehl. 

Mach einfach:

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

Nun, da Sie an if denken, wie Sie den Exit-Status des nachfolgenden Befehls prüfen (komplett mit Semikolon). Warum nicht die Quelle der Zeichenfolge, die Sie testen, noch einmal ü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
#...

Die -q-Option bewirkt, dass grep nichts ausgibt, da nur der Rückgabecode gewünscht wird. <<< bewirkt, dass die Shell das nächste Word erweitert und als Eingabe für den Befehl verwendet, eine einzeilige Version des <<-Dokuments (ich bin nicht sicher, ob dies Standard oder ein Bashmus ist).

131
Mark Baker

Die akzeptierte Antwort ist am besten, aber da es mehr als einen Weg gibt, dies zu tun, gibt es eine andere Lösung:

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

${var/search/replace} ist $var, wobei die erste Instanz von search durch replace ersetzt wird, falls sie gefunden wird ($var wird nicht geändert). Wenn Sie versuchen, foo durch nichts zu ersetzen, und die Zeichenfolge geändert wurde, wurde offensichtlich foo gefunden.

81
ephemient

Es gibt also viele nützliche Lösungen für die Frage - aber welche ist am schnellsten/nutzt die geringste Ressource?

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.92user 0.06system 0:02.99elapsed 99%CPU

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

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

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

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

(doContain war in F. Houris Antwort)

Und zum Kichern:

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

So gewinnt die einfache Substitutionsoption prädikativ, ob in einem erweiterten Test oder in einem Fall. Der Fall ist tragbar.

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

41
Paul Hedderly

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 von den Eigenschaften von Bash Shell abhängig.

Das ---Argument ist reine POSIX-Paranoia und wird verwendet, um gegen Eingabezeichenfolgen zu schützen, die Optionen wie --abc oder -a ähneln.

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 miteinander verbunden werden.

26
kevinarpe

Wie wäre es damit:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi
15
Stefan

Wie Paulus in seinem Leistungsvergleich erwähnte:

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 die Antwort "case" $ string "in" von Marcus, ist jedoch etwas einfacher zu lesen als die Antwort in der case-Anweisung. Beachten Sie auch, dass dies viel langsamer ist als die Verwendung einer case-Anweisung. Verwenden Sie sie, wie Paulus betont hat, nicht in einer Schleife.

11
Samuel

Bash4 + Beispiele. Hinweis: Wenn Sie keine Anführungszeichen verwenden, führt dies zu Problemen, wenn Wörter Leerzeichen usw. enthalten. Zitieren Sie immer in bash IMO.

Hier einige Beispiele für BASH4 +:

Beispiel 1, überprüfen Sie 'Ja' in Zeichenfolge (Groß- und Kleinschreibung wird nicht berücksichtigt):

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

Beispiel 2, überprüfen Sie 'Ja' in Zeichenfolge (Groß- und Kleinschreibung wird nicht berücksichtigt):

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

Beispiel 3, überprüfen Sie 'Ja' in der Zeichenfolge (Groß- und Kleinschreibung beachten):

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

Beispiel 4, überprüfen Sie 'Ja' in der Zeichenfolge (Groß- und Kleinschreibung beachten):

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

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

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

Beispiel 6, exakte Übereinstimmung (Groß- und Kleinschreibung wird nicht berücksichtigt):

     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.

10
Mike Q

Diese Stack Overflow-Antwort war der einzige, der Leerzeichen einfängt und Striche anlegt:

# For null cmd arguments checking   
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
10
Yordan Georgiev

Eins ist:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
9
chemila
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
8
Jahid

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

Dasselbe 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

Originalquelle: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html

5
Jadu Saikia

Mein .bash_profile und wie ich grep Verwendet habe, wenn der PATH meine 2 bin-Verzeichnisse enthielt, 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
5

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 der Teilzeichenfolge aus der Zeichenfolge zu entfernen

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

5
ride

Ich habe diese Funktionalität ziemlich häufig benötigt, daher verwende ich in meinem .bashrc eine selbstgebaute Shell-Funktion, die es mir erlaubt, sie so oft wie nötig wiederzuverwenden, mit einem leicht zu merkenden Namen:

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

Um zu testen, ob $string1 (etwa abc ) in $string2 (beispielsweise 123abcABC ) enthalten ist, muss ich nur stringinstring "$string1" "$string2" ausführen und beispielsweise den Rückgabewert prüfen

stringinstring "$str1" "$str2"  &&  echo YES  ||  echo NO
4
Kurt Pfeifle

Probieren Sie oobash aus. Dies ist eine OO-ähnliche String-Bibliothek 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, -zfill, ,CODE__.

Schauen Sie sich das Beispiel an:

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

oobash ist verfügbar unter Sourceforge.net .

3
andreas

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
3
Eduardo Cuomo

Ich benutze diese Funktion (eine Abhängigkeit ist nicht enthalten, aber offensichtlich). Es besteht die unten gezeigten Tests. Wenn die Funktion einen Wert> 0 zurückgibt, wurde der String gefunden. Sie können stattdessen auch 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 "(" "'[email protected] (dev,web)'" | assert_eq 11
   str_instr ")" "'[email protected] (dev,web)'" | assert_eq 19
   str_instr "[" "'[email protected] [dev,web]'" | assert_eq 11
   str_instr "]" "'[email protected] [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
}
2
Ethan Post

Erweiterung der hier beantworteten Frage https://stackoverflow.com/a/8811800/712666

Diese Lösung arbeitet 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*"
1