Unterstützt bash Rückverweise bei der Parametererweiterung?

15

Ich habe eine Variable mit dem Namen , descrdie eine Zeichenfolge enthalten können Blah: -> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foousw. Ich will das bekommen -> r1-ae0-2, einen -> s7-Gi0-0-1:1-USTeil von der Saite. Im Moment nutze ich descr=$(grep -oP '\->\s*\S+' <<< "$descr"dafür. Gibt es einen besseren Weg, dies zu tun? Ist dies auch mit Parametererweiterung möglich?

Martin
quelle

Antworten:

20

ksh93und zshhaben Rückverweis (oder genauer 1 , Verweise auf Capture-Gruppen in der Ersetzung) Unterstützung im Inneren ${var/pattern/replacement}, nicht 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

(In der mkshManpage wird auch erwähnt, dass zukünftige Versionen dies ${KSH_MATCH[1]}für die erste Erfassungsgruppe unterstützen werden. Ab dem 25.04.2017 noch nicht verfügbar).

Mit können bashSie jedoch Folgendes tun:

$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
  printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2

Welches ist besser, da es prüft, ob das Muster zuerst 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 erhalten zshSie die volle Leistung von PCREs 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 mehrmals vorkommt, ändert sich das Verhalten bei all diesen Lösungen. Keiner von ihnen gibt Ihnen jedoch eine durch Zeilenumbrüche getrennte Liste aller Übereinstimmungen wie in Ihrer GNU- grepbasierten Lösung.

Dazu müssten Sie die Schleife von Hand 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 zshkönnen Sie auf diese Art von 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 Übereinstimmungen mit einer früheren Gruppe verweist. Beispielsweise entspricht der \(.\)\1reguläre Basisausdruck einem einzelnen Zeichen, gefolgt von demselben Zeichen (es entspricht ein aa, nicht ein ab). Dies \1ist ein Rückverweis auf diese \(.\)Erfassungsgruppe im selben Muster.

ksh93Unterstützt Rückverweise in seinen Mustern ( ls -d -- @(?)\1listet beispielsweise die Dateinamen auf, die aus zwei identischen Zeichen bestehen), keine anderen Shells. Standard-BREs und -PCREs unterstützen Rückverweise, nicht jedoch Standard-ERE, obwohl einige ERE-Implementierungen dies als Erweiterung unterstützen. bash‚s [[ foo =~ re ]]Verwendungen EREs.

[[ aa =~ (.)\1 ]]

wird nicht passen, aber

re='(.)\1'; [[ aa =~ $re ]]

kann, wenn die EREs des Systems dies unterstützen.

Stéphane Chazelas
quelle
9

Sie möchten alles bis zum Ersten ␣->␣(ohne "Pfeil") und nach dem Letzten ␣/(einschließlich Leerzeichen und Schrägstrich) löschen .

string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}

$stringwird jetzt sein -> r1-ae0-2.

Die gleichen zwei Substitutionen würden sich -> s7-Gi0-0-1:1-US / Fooin -> s7-Gi0-0-1:1-US.

Kusalananda
quelle
3

Dies definitiv zu beantworten ist unmöglich, ohne das genaue Format zu kennen, das jede Nachricht annimmt. Im Allgemeinen können Sie jedoch bestimmte Felder drucken, indem Sie Folgendes verwenden cut:

$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US

Oder Sie drucken jede n-te Spalte 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
l0b0
quelle