with - bash substring




String enthält in Bash (14)

Kompatible Antwort

Da es bereits viele Antworten gibt, die Bash-spezifische Funktionen verwenden, gibt es eine Möglichkeit, unter Shells mit schlechterem Funktionsumfang, 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, 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 der gleichen Demo, getestet unter den gleichen Shells:

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 doppelte oder doppelte Anführungszeichen und / oder doppelte Anführungszeichen 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ünter's Kommentar vorgeschlagen , vermeidet -o switche:

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

Mit leeren Strings:

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

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 ein bisschen ungeschickt aus.


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 Eigenschaften der Bash-Shell.

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

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


Einer ist:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'

Es gibt also viele nützliche Lösungen für die Frage - aber welche ist am schnellsten / verwendet 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!

Daher gewinnt die einfache Substitutionsoption prägnant, ob in einem erweiterten Test oder in einem Fall. Der Koffer ist tragbar.

Piping auf 100000 Greps ist vorhersehbar schmerzhaft! Die alte Regel über die Verwendung von externen Dienstprogrammen ohne Notwendigkeit gilt.


Ich benutze diese Funktion (eine Abhängigkeit nicht enthalten, aber offensichtlich). Es besteht die folgenden Tests. Wenn die Funktion einen Wert> 0 zurückgibt, wurde die Zeichenfolge gefunden. Sie könnten ebenso einfach 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
}

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

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

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 die Teilzeichenfolge vorhanden


Mein .bash_profile und wie ich grep verwendet habe, wenn der PATH meine 2 bin-Verzeichnisse enthält, füge 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

Sie sollten sich daran erinnern, dass das Shell-Scripting weniger eine Sprache, sondern mehr eine Sammlung von Befehlen ist. Instinktiv denken Sie, dass diese "Sprache" erfordert, dass Sie einem if mit einem [ oder einem [[ . Beides sind nur Befehle, die einen Exit-Status zurückgeben, der Erfolg oder Fehlschlag anzeigt (genau wie jeder andere Befehl). Aus diesem Grund würde ich grep und nicht den [ Befehl.

Mach einfach:

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

Jetzt, wo Sie daran denken, den Exit-Status des folgenden Befehls zu testen (mit Semikolon abgeschlossen). Warum überlegst du nicht die Quelle der Zeichenfolge, die du testest?

## 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 Option -q dass grep nichts ausgibt, da wir nur den Rückkehrcode wünschen. <<< dass die Shell das nächste Wort erweitert und es als Eingabe für den Befehl verwendet, eine einzeilige Version des << here-Dokuments (ich bin mir nicht sicher, ob das Standard oder ein Bashismus ist).


Versuchen oobash es ist eine OO-style String-Bibliothek für bash 4. Es hat Unterstützung für deutsche Umlaute. Es ist in bash geschrieben. Viele Funktionen sind verfügbar: -base64Decode , -base64Encode , -capitalize , -charAt , -concat , -count , -endsWith , -equals , -equalsIgnoreCase , -reverse , -hashCode , -indexOf , -isAlnum , -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 .

Schau dir das enthaltene Beispiel an:

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

oobash ist verfügbar unter Sourceforge.net .


Wie Paul 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 "case" $ - Zeichenkette "in" -Antwort von Marcus, ist aber etwas einfacher zu lesen als die Antwort der Fallanweisung. Beachten Sie auch, dass dies wesentlich langsamer ist als die Verwendung einer case-Anweisung, die, wie Paul betonte, nicht in einer Schleife verwendet wird.


Wie wäre es damit:

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

Diese Stapelüberlauf-Antwort war die einzige, die Leerzeichen und Bindestriche enthielt:

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

[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"




substring