Frage String enthält einen Teilstring in Bash


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

Woher ?? 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.


1742
2017-10-23 12:37


Ursprung


Antworten:


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 Nadelfolge zwischen doppelten Anführungszeichen stehen müssen und die * Wildcards sollten draußen sein.


2487
2017-10-23 12:55



Wenn Sie den Regex-Ansatz bevorzugen:

string='My string';

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

386
2017-10-23 20:10



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

239
2017-10-23 12:47



Kompatible Antwort

Da es bereits viele Antworten mit Bash-spezifischen Funktionen gibt, gibt es einen Weg, unter Shells mit schlechteren Eigenschaften zu arbeiten, wie :

[ -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 getestet , ,  und  (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 eine Funktion

Wie von @EeroAaltonen gefragt, 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'.

Beachten: Du musst flüchten oder doppelte Anführungszeichen und / oder Anführungszeichen einfügen:

$ 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 getestet ,  und natürlich :

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 vorgeschlagen Adrian Günters Kommentarvermeidend -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

135
2017-12-08 23:06



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 folgen if mit einem [ oder ein [[. 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 verwenden grepund nicht die [ Befehl.

Mach einfach:

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

Jetzt, an die du denkst if zum Testen des Exit-Status des folgenden Befehls (komplett mit Semikolon). 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
#...

Das -q Diese Option bewirkt, dass grep nichts ausgibt, da wir nur den Rückkehrcode benötigen. <<< Die Shell erweitert das nächste Wort und verwendet es als Eingabe für den Befehl, eine einzeilige Version von << hier Dokument (ich bin mir nicht sicher, ob das Standard oder ein Bashismus ist).


110
2017-10-27 14:57



Die akzeptierte Antwort ist die beste, aber da es mehr als eine Möglichkeit gibt, dies zu tun, hier ist eine andere Lösung:

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

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


73
2017-10-23 14:35



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.


31
2017-08-27 19:42



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 reine POSIX-Paranoia, die verwendet wird, um vor Eingabezeichenfolgen zu schützen, die Optionen ähnlich sind, wie z --abc oder -a.

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


22
2017-12-01 15:41



Wie wäre es damit:

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

11
2018-02-09 06:15