Wie kann man in bash feststellen, ob eine Zeichenfolge eine Teilzeichenfolge einer anderen ist?

49

Ich möchte sehen, ob sich eine Zeichenfolge in einem Teil einer anderen Zeichenfolge befindet.
z.B:

'ab' in 'abc' -> true
'ab' in 'bcd' -> false

Wie kann ich dies unter der Bedingung eines Bash-Skripts tun?

Lucio
quelle

Antworten:

27

Sie können das Formular verwenden, ${VAR/subs}in dem VARdie größere Zeichenfolge enthalten ist und subsdie Teilzeichenfolge, die Sie suchen:

my_string=abc
substring=ab
if [ "${my_string/$substring}" = "$my_string" ] ; then
  echo "${substring} is not in ${my_string}"
else
  echo "${substring} was found in ${my_string}"
fi

Dies funktioniert, weil ${VAR/subs}gleich ist, $VARaber das erste Vorkommen der Zeichenfolge subsentfernt wird, insbesondere, wenn $VARdas Wort nicht enthalten ist subs, wird es nicht geändert.

edwin
quelle
Ich denke, dass Sie die Reihenfolge der echoAussagen ändern sollten . Weil ich bekommeab is not in abc
Lucio
Sie haben Recht! : P
edwin
Mmm .. Nein, das Skript ist falsch. So bekomme ich ab was found in abc, aber wenn ich benutze, substring=zbekomme ichz was found in abc
Lucio
1
Jetzt verstehe ich ab is not in abc. Aber z was found in abc. Das ist lustig: D
Lucio
1
Duh! Die Echos waren gleich zu Beginn! XD
Edwin
47

[[ "bcd" =~ "ab" ]]
[[ "abc" =~ "ab" ]]

Die Klammern sind für den Test, und da es sich um doppelte Klammern handelt, kann es so einige zusätzliche Tests geben =~.

Sie könnten dieses Formular also so ähnlich verwenden

var1="ab"
var2="bcd"
if [[ "$var2" =~ "$var1" ]]; then
    echo "pass"
else
    echo "fail"
fi

Edit: korrigiert "= ~", hatte gekippt.

zurückhaltend
quelle
1
Ich bekomme failmit diesen Parametern:var2="abcd"
Lucio
3
@ Lucio Die richtige ist [[ $string =~ $substring ]]. Ich habe die Antwort aktualisiert.
Eric Carvalho
12

Verwenden von Bash- Dateinamenmustern (auch "Glob" -Muster genannt)

substr=ab
[[ abc == *"$substr"* ]] && echo yes || echo no    # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no    # no
Glenn Jackman
quelle
if [["$ JAVA_OPTS"! = "-XX: + UseCompressedOops" ]]; dann exportiere JAVA_OPTS = "$ JAVA_OPTS -XX: + UseCompressedOops"; fi
Mike Slinn
10

Die folgenden zwei Ansätze funktionieren in jeder POSIX-kompatiblen Umgebung, nicht nur in bash:

substr=ab
for s in abc bcd; do
    if case ${s} in *"${substr}"*) true;; *) false;; esac; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done
substr=ab
for s in abc bcd; do
    if printf %s\\n "${s}" | grep -qF "${substr}"; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done

Beide der obigen Ausgaben:

'abc' contains 'ab'
'bcd' does not contain 'ab'

Ersteres hat den Vorteil, dass kein separater grepProzess gestartet wird.

Beachten Sie, dass ich printf %s\\n "${foo}"anstelle von verwenden, echo "${foo}"weil echomangeln könnte, ${foo}wenn es Backslashes enthält.

Richard Hansen
quelle
Die erste Version funktioniert perfekt, um die Teilzeichenfolge des Monitornamens in der Liste der xrandrin der Variablen gespeicherten Monitornamen zu finden. +1 und Willkommen bei 1K rep Club :)
WinEunuuchs2Unix
6

Shell-Case-Anweisung

Dies ist die portabelste Lösung, die auch auf alten Bourne-Shells und Korn-Shells funktioniert

#!/bin/bash
case "abcd" in
    *$1*) echo "It's a substring" ;;
    *) echo "Not a substring" ;;
esac

Probelauf:

$ ./case_substr.sh "ab"                                                                                           
It's a substring
$ ./case_substr.sh "whatever"                                                                                     
Not a substring

Beachten Sie, dass Sie müssen nicht speziell verwenden echoSie verwenden können , exit 1und exit 0Erfolg oder Misserfolg zu bedeuten.

Wir könnten auch eine Funktion erstellen (die bei Bedarf in großen Skripten verwendet werden kann) mit bestimmten Rückgabewerten (0 bei Übereinstimmung, 1 bei keiner Übereinstimmung):

$ ./substring_function.sh                                  
ab is substring

$ cat substring_function.sh                                
#!/bin/sh

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

main(){
   if is_substring "ab" "abcdefg"
   then
       echo "ab is substring"
   fi
}

main $@

grep

$ grep -q 'ab' <<< "abcd" && echo "it's a substring" || echo "not a substring"                                    
it's a substring

Dieser spezielle Ansatz ist bei if-else-Anweisungen in nützlich bash. Meistens auch tragbar

AWK

$ awk '$0~/ab/{print "it is a substring"}' <<< "abcd"                                                             
it is a substring

Python

$ python -c 'import sys;sys.stdout.write("it is a substring") if "ab" in sys.stdin.read() else exit(1)' <<< "abcd"
it is a substring

Rubin

$ ruby -e ' puts "is substring" if  ARGV[1].include? ARGV[0]'  "ab" "abcdef"                                             
is substring
Sergiy Kolodyazhnyy
quelle
+1 für mehr als alle anderen. Mir ist aufgefallen, dass hier und auf anderen Stack-Exchange-Sites keine Antwort den Offset des Teilstrings innerhalb des Strings zurückgibt. Welches ist heute Abend Mission :)
WinEunuuchs2Unix
@ WinEunuuchs2Unix Willst du das in bash machen?
Sergiy Kolodyazhnyy
Ja und Nein. Ich mache ein Frankenstein-Projekt, in dem Python alle Metadaten für gmail.com-Nachrichten abruft und es mit einer Bash-Analyse analysiert und eine GUI-Liste mit Drilldown-Funktionen anzeigt. Die Antwort habe ich hier gefunden: stackoverflow.com/questions/5031764/…
WinEunuuchs2Unix
@ WinEunuuchs2Unix OK. Hört sich interessant an. Ich persönlich würde es vorziehen, alles in Python zu analysieren. Es bietet weit mehr Möglichkeiten für die Textverarbeitung als nur Bash.
Sergiy Kolodyazhnyy
Ich kenne Ihre Vorlieben seit ungefähr zwei Jahren und respektiere sie. Aber ich lerne nur Python und es scheint mir umständlich zu sein, dich dazu zu bringen, darin zu arbeiten. Ganz zu schweigen von der ganzen Array-Verarbeitung, mit der ich mich in bash bereits auskenne. Aber zumindest habe ich mein erstes Python-Skript geschrieben, um alles aus googles gmail.com in eine Linux-Flatfile zu saugen, oder? :)
WinEunuuchs2Unix
5

Beachten Sie die [[und ":

[[ $a == z* ]]   # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

[ $a == z* ]     # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).

Also, wie @glenn_jackman sagte, aber bedenken Sie, dass, wenn Sie den gesamten zweiten Term in doppelte Anführungszeichen setzen, der Test auf wörtliche Übereinstimmung umgestellt wird .

Quelle: http://tldp.org/LDP/abs/html/comparison-ops.html

Campa
quelle
4

Ähnlich wie Edwins Antwort, jedoch mit verbesserter Portabilität für posix & ksh und einem Hauch weniger laut als bei Richard:

substring=ab

string=abc
if [ "$string" != "${string%$substring*}" ]; then
    echo "$substring IS in $string"
else
    echo "$substring is NOT in $string"
fi

string=bcd
if [ "$string" != "${string%$substring*}" ]; then
    echo "$string contains $substring"
else
    echo "$string does NOT contain $substring"
fi

Ausgabe:

abc contains ab
bcd does NOT contain ab
Laubster
quelle