
Ich habe eine Variable namens , die eine Zeichenfolge , usw. descr
enthalten kann. Ich möchte den , -Teil aus der Zeichenfolge erhalten. Im Moment verwende ich dafür. Gibt es eine bessere Möglichkeit, dies zu tun? Ist dies auch mit Parametererweiterung möglich?Blah: -> r1-ae0-2 / [123]
-> s7-Gi0-0-1:1-US / Foo
-> r1-ae0-2
-> s7-Gi0-0-1:1-US
descr=$(grep -oP '\->\s*\S+' <<< "$descr"
Antwort1
ksh93
und zsh
verfügen über Rückverweise (oder genauer 1 , Verweise auf Erfassungsgruppen im Ersetzungs-)Unterstützung innerhalb von ${var/pattern/replacement}
, nicht innerhalb von bash
.
ksh93
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ printf '%s\n' "${var/*@(->*([[:space:]])+([^[:space:]]))*/\1}"
-> r1-ae0-2
zsh
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ set -o extendedglob
$ printf '%s\n' "${var/(#b)*(->[[:space:]]#[^[:space:]]##)*/$match[1]}"
-> r1-ae0-2
( mksh
Auf der Manpage wird auch erwähnt, dass zukünftige Versionen dies ${KSH_MATCH[1]}
für die erste Erfassungsgruppe unterstützen werden. Stand 25.04.2017 noch nicht verfügbar).
Mit können Sie jedoch Folgendes bash
tun:
$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2
Das ist besser, da zuerst geprüft wird, ob das Muster gefunden wird.
Wenn die regulären Ausdrücke Ihres Systems \s
/ unterstützen \S
, können Sie auch Folgendes tun:
re='->\s*\S+'
[[ $var =~ $re ]]
Mit zsh
können Sie die volle Leistung von PCREs nutzen mit:
$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2
Mit zsh -o extendedglob
siehe auch:
$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2
Tragbar:
$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2
Wenn das Muster in der Zeichenfolge mehrfach vorkommt, ist das Verhalten bei allen diesen Lösungen unterschiedlich. Allerdings erhalten Sie bei keiner von ihnen eine durch Zeilenumbrüche getrennte Liste aller Übereinstimmungen wie bei Ihrer GNU-basierten grep
Lösung.
Dazu müssen Sie die Schleife manuell ausführen. Zum Beispiel mit bash
:
re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
printf '%s\n' "${BASH_REMATCH[1]}"
var=${BASH_REMATCH[2]}
done
Mit zsh
könnten Sie auf diesen Trick zurückgreifen, um alle Übereinstimmungen in einem Array zu speichern:
set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches
1 Rückverweise bezeichnen häufiger ein Muster, das auf etwas verweist, das von einer früheren Gruppe abgeglichen wurde. Beispielsweise \(.\)\1
gleicht der grundlegende reguläre Ausdruck ein einzelnes Zeichen ab, gefolgt von demselben Zeichen (er gleicht auf aa
, nicht auf ab
). Das \1
ist ein Rückverweis auf diese \(.\)
Erfassungsgruppe im gleichen Muster.
ksh93
unterstützt Rückverweise in seinen Mustern ( ls -d -- @(?)\1
listet beispielsweise die Dateinamen auf, die aus zwei identischen Zeichen bestehen), andere Shells nicht. Standard-BREs und PCREs unterstützen Rückverweise, aber kein Standard-ERE, obwohl einige ERE-Implementierungen es als Erweiterung unterstützen. bash
's [[ foo =~ re ]]
verwendet EREs.
[[ aa =~ (.)\1 ]]
wird nicht übereinstimmen, aber
re='(.)\1'; [[ aa =~ $re ]]
möglich, wenn die EREs des Systems dies unterstützen.
Antwort2
Sie möchten alles bis zum ersten ␣->␣
(ohne den „Pfeil“) und nach dem letzten ␣/
(einschließlich Leerzeichen und Schrägstrich) löschen.
string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}
$string
wird jetzt sein -> r1-ae0-2
.
Dieselben beiden Ersetzungen würden zu -> s7-Gi0-0-1:1-US / Foo
werden -> s7-Gi0-0-1:1-US
.
Antwort3
Eine definitive Antwort darauf ist ohne Kenntnis des genauen Formats nicht möglich.jedenNachricht dauert. Als allgemeine Vorgehensweise können Sie jedoch bestimmte Felder ausdrucken mit cut
:
$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US
Oder du kannstjede n-te Spalte drucken mitawk
:
$ awk -F' ' '{ for (i=2;i<=NF;i+=4) print $i }' <<< '-> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foo'
r1-ae0-2
s7-Gi0-0-1:1-US