Suchen Sie eine Zeichenfolge, während Sie einen Teil davon kennen, und geben Sie die Zeichenfolge zurück

8

Ich habe zum Beispiel eine Zeichenfolge

"Icecream123 AirplaneBCD CompanyTL1 ComputerYU1"

Angenommen, ich weiß, dass meine Zeichenfolge mit Sicherheit den Teilstring IceCream enthält, aber ich weiß nicht, was darauf folgt.

Es könnte 123 sein wie in meinem Beispiel oder es könnte etwas anderes sein.

Während ich mit grep feststellen kann, ob in meiner Zeichenfolge mit dem folgenden Befehl "Icecream" -Substring vorhanden ist

echo $string | grep -oF 'Icecream';

Welches wird gedruckt

Icecream

Ich möchte mit einem Befehl den gesamten Teilstring drucken, der in meinem Beispiel ist

Icecream123

Natürlich ist das, was Icecream folgt, zufällig und vorher nicht bekannt, also kann ich es nicht einfach tun

$SUBSTRING=$(echo $string | grep -oF 'Icecream')
$SUBSTRINGTRAIL=123
echo $SUBSTRING$SUBSTRINGTRAIL
Sonamor
quelle
Ist der Teilstring fest / statisch - immer "Icecream" oder ist er variabel?
Jeff Schaller
Wird ein Leerzeichen das Ende des gewünschten Suffixes anzeigen?
Jeff Schaller
@ JeffSchaller Leider weiß ich das nicht. Ich erhalte tatsächlich eine mehrzeilige Ausgabe von einem anderen Befehl, den ich in einer Variablen speichere. Diese Variable ist mein $ string. Wenn sie wiedergegeben wird, wird die mehrzeilige Ausgabe als Signallinie mit einem Leerzeichen dazwischen angezeigt. Ich weiß eigentlich nicht, ob das ein Leerzeichen oder ein Sonderzeichen wie LF ist. Ich dachte, dass es Platz ist.
Sonamor
Ich meine, Icecream123 AirplaneBCDdu willst zum Beispiel anhalten 123. Liegt das daran, dass nach der 3 ein Leerzeichen steht oder etwas anderes?
Jeff Schaller
1
Wenn Sie sich nicht sicher sind, was Ihre Daten sind, ist es schwierig, eine geeignete Lösung zu schreiben. Bei allen bisherigen Antworten wird davon ausgegangen, dass sich Ihre Daten in einer Zeile befinden, wie Sie es gezeigt haben. Ich habe versucht herauszufinden, was Ihr Begrenzer ist - wo der "nachfolgende" Teil aufhören sollte.
Jeff Schaller

Antworten:

15

Wenn Sie grepPerl-kompatible reguläre Ausdrücke unterstützen, können Sie nicht gierig bis zur nächsten Wortgrenze übereinstimmen:

echo "$string" | grep -oP 'Icecream.*?\b'

Andernfalls stimmen Sie mit der längsten Folge von nicht leeren Zeichen überein:

echo "$string" | grep -o 'Icecream[^[:blank:]]*'

Oder behalten Sie alles in der Shell und entfernen Sie die längste nachfolgende Zeichenfolge, beginnend mit einem Leerzeichen:

echo "${string%% *}"
Steeldriver
quelle
2
Für die PCRE würde ich 'Icecream\S+'einige nicht leere Zeichen verwenden.
Glenn Jackman
Vielen Dank für Ihre Kommentare. Leider scheint meine Version von grep Perl Regex nicht zu unterstützen. Könnten Sie weitere Details zu Ihrer dritten Option hinzufügen? Ich bin mir nicht ganz sicher, wie ich es umsetzen soll.
Sonamor
Nach einigen weiteren Tests scheint es, dass entweder "$ string" | verwendet wird grep -oP 'Icecream. *? \ b' oder 'Icecream \ S +' macht den Job. Vielen Dank
Sonamor
Es ist wirklich verwirrend, dass Ihre $ string-Variable zwar eine Zeichenfolge ist, Sie sie jedoch in doppelte Anführungszeichen setzen müssen!
Sonamor
@ Sonamor In diesem Fall ist das Zitieren nicht unbedingt erforderlich. aber es gibt so viele Fälle , in denen es ist , dass es eine gute Gewohnheit ist , in zu erhalten. Siehe zum Beispiel Wann ist eine doppelte Anführungszeichen erforderlich?
Steeldriver
7

Mit einem grep, der weiß über -o:

$ printf '%s\n' "$string" | grep -o '\<Icecream[^[:blank:]]*'
Icecream123

Das Muster \<Icecream[^[:blank:]]*entspricht der Zeichenfolge Icecream( Ivor der ein Nicht-Wort-Zeichen oder der Zeilenanfang steht), gefolgt von null oder mehr Nicht-Leerzeichen (keine Leerzeichen oder Tabulatoren).


Verwenden von awk:

$ printf '%s\n' "$string" | awk -v RS=' ' '/^Icecream/'       
Icecream123

Das awkProgramm unterteilt die Zeichenfolge in durch Leerzeichen getrennte Datensätze und testet jeden einzelnen. Es werden diejenigen gedruckt, die mit der Zeichenfolge beginnen Icecream.

Mit mawkoder GNU awkkönnen Sie auch verwenden

printf '%s\n' "$string" | awk -v RS='[[:blank:]]' '/^Icecream/'

da sie RSals regulärer Ausdruck interpetieren, wenn er mehr als ein Zeichen enthält.


Mit sed, ähnlich wie mit grep:

$ printf '%s\n' "$string" | sed 's/.*\(\<Icecream[^[:blank:]]*\).*/\1/'
Icecream123

Verwenden von /bin/sh:

set -- Icecream123 AirplaneBCD CompanyTL1 ComputerYU1
for string; do
    case $string in
        Icecream*)
            printf '%s\n' "$string"
            break
    esac
done

Perl (mit ein wenig Hilfe von tr):

$ printf '%s\n' "$string" | tr ' ' '\n' | perl -ne '/Icecream\S*/ && print'
Icecream123

oder nur

$ printf '%s\n' "$string" | perl -ne '/(Icecream\S*)/ && print $1, "\n"'
Icecream123
Kusalananda
quelle
Oder teilen Sie sich in Zeilen auf und passen Sie den Schlüssel an:echo "$string" | grep -o '\S\+' | grep "Icecream"
Isaac
7

Seit du bash getaggt hast:

[[ $string =~ (Icecream[^ ]*) ]] && result=${BASH_REMATCH[1]}

Allgemeiner für einen Suchbegriff in $search:

[[ $string =~ ($search[^ ]*) ]] && result=${BASH_REMATCH[1]}

... oder mit Parametererweiterung:

# remove any leading text up to -and through- the search text:
x=${string##*$search}

# remove any trailing space onwards
result=$search${x%% *}
Jeff Schaller
quelle
2

Zum Beispiel, wenn Sie verwenden GNU grep:

$ echo "Icecream123 AirplaneBCD CompanyTL1 ComputerYU1" | grep -oP '\bIcecream.*?(\s|$)' --color

Es verwendet PCRE.

Arkadiusz Drabczyk
quelle
1

Ein bisschen einfacher vielleicht, zumal Sie sagen, dass Ihre Version von grep Perl Regex nicht unterstützt:

$ echo $string | tr ' ' '\n' | grep 'Icecream' Icecream123

Das trteilt die Zeichenfolge in Zeilen auf, indem alle Leerzeichen durch Zeilenumbrüche ersetzt werden. Dann können Sie grepleicht verwenden.

Sie können auch Folgendes schreiben, um nur das zu erhalten, was dem gesuchten Wort folgt:

$ echo $string | tr ' ' '\n' | sed -n 's/Icecream//p' 123

Gesetz29
quelle