Czy bash obsługuje odwołania referencyjne w rozszerzaniu parametrów?


15

Mam zmienną o nazwie descr, które mogą zawierać łańcuch Blah: -> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Fooitp Chcę uzyskać -> r1-ae0-2, -> s7-Gi0-0-1:1-USczęść z łańcucha. W tej chwili używam descr=$(grep -oP '\->\s*\S+' <<< "$descr"do tego. Czy jest na to lepszy sposób? Czy można to również zrobić z rozszerzaniem parametrów?

Odpowiedzi:


20

ksh93i zshmieć w sobie odniesienia (lub dokładniej 1 , odniesienia do grup przechwytywania w zastępstwie) ${var/pattern/replacement}, nie 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

( mkshstrona ${KSH_MATCH[1]}podręcznika wspomina również, że przyszłe wersje będą go obsługiwać dla pierwszej grupy przechwytywania. Jeszcze niedostępne od 25.04.2017).

Jednak za pomocą bashmożesz:

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

Co jest lepsze, ponieważ sprawdza, czy wzorzec zostanie znaleziony jako pierwszy.

Jeśli obsługa wyrażeń regularnych w twoim systemie \s/ \S, możesz także:

re='->\s*\S+'
[[ $var =~ $re ]]

Dzięki zshmożesz uzyskać pełną moc PCRE dzięki:

$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2

Z zsh -o extendedglobzobacz także:

$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2

Przenośny:

$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2

Jeśli w ciągu występuje kilka wystąpień wzorca, zachowanie będzie się różnić dla wszystkich tych rozwiązań. Jednak żadna z nich nie da ci oddzielnej listy wszystkich dopasowań, jak w twoim greprozwiązaniu opartym na GNU.

Aby to zrobić, musisz ręcznie wykonać pętlę. Na przykład z bash:

re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
  printf '%s\n' "${BASH_REMATCH[1]}"
  var=${BASH_REMATCH[2]}
done

Dzięki zshmożesz skorzystać z tego rodzaju sztuczki, aby zapisać wszystkie dopasowania w tablicy:

set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches

1 odniesienia wsteczne częściej oznaczają wzorzec, który odwołuje się do tego, co pasowało do wcześniejszej grupy. Na przykład \(.\)\1podstawowe wyrażenie regularne dopasowuje pojedynczy znak, po którym następuje ten sam znak (pasuje on aa, a nie on ab). Jest \1to odniesienie do tej \(.\)grupy przechwytywania według tego samego wzorca.

ksh93obsługuje wzorce wsteczne (na przykład ls -d -- @(?)\1wyświetla nazwy plików składające się z dwóch identycznych znaków), a nie inne powłoki. Standardowe BRE i PCRE obsługują referencje wsteczne, ale nie standardowe ERE, chociaż niektóre implementacje ERE obsługują je jako rozszerzenie. bash„S [[ foo =~ re ]]Używa ERES.

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

nie będzie pasować, ale

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

może, jeśli ERE systemu to obsługuje.


9

Chcesz usunąć wszystko do pierwszego ␣->␣(bez „strzałki”) i po ostatnim ␣/(łącznie ze spacją i ukośnikiem).

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

$stringbędzie teraz -> r1-ae0-2.

Te same dwie zamiany zamieniłyby się -> s7-Gi0-0-1:1-US / Foow -> s7-Gi0-0-1:1-US.


3

Ostateczne udzielenie odpowiedzi jest niemożliwe bez znajomości dokładnego formatu każdej wiadomości. Jednak jako ogólne podejście można wydrukować określone pola przy użyciu cut:

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

Lub możesz wydrukować każdą n-tą kolumnę, używającawk :

$ 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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.