Поддерживает ли bash обратные ссылки при расширении параметров?

Поддерживает ли bash обратные ссылки при расширении параметров?

У меня есть переменная с именем descr, которая может содержать строку 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"для этого. Есть ли лучший способ сделать это? Можно ли также сделать это с помощью расширения параметров?

решение1

ksh93и zshиметь поддержку обратных ссылок (или, точнее , ссылок на группы захвата в замене) внутри ${var/pattern/replacement}, а не 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на странице руководства также упоминается, что будущие версии будут поддерживать его ${KSH_MATCH[1]}для первой группы захвата. По состоянию на 25.04.2017 еще недоступно).

Однако с помощью bashвы можете сделать:

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

Что лучше, так как сначала проверяется, найден ли шаблон.

Если регулярные выражения вашей системы поддерживают \s/ \S, вы также можете сделать:

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

С помощью zshвы можете получить полную мощность PCRE с:

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

С zsh -o extendedglob, см. также:

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

Портативно:

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

Если в строке есть несколько вхождений шаблона, поведение будет разным для всех этих решений. Однако ни одно из них не даст вам разделенный новой строкой список всех совпадений, как в вашем grepрешении на основе GNU.

Чтобы сделать это, вам нужно будет сделать цикл вручную. Например, с помощью bash:

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

С помощью zshможно прибегнуть к такому трюку, чтобы сохранить все совпадения в массиве:

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

1 обратные ссылки чаще всего обозначают шаблон, который ссылается на то, что было сопоставлено более ранней группой. Например, базовое \(.\)\1регулярное выражение соответствует одному символу, за которым следует тот же символ (соответствует aa, а не ab). Это \1обратная ссылка на эту \(.\)группу захвата в том же шаблоне.

ksh93поддерживает обратные ссылки в своих шаблонах (например, ls -d -- @(?)\1перечислит имена файлов, которые состоят из двух одинаковых символов), но не другие оболочки. Стандартные BRE и PCRE поддерживают обратные ссылки, но не стандартные ERE, хотя некоторые реализации ERE поддерживают их как расширение. bash's [[ foo =~ re ]]использует ERE.

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

не будет соответствовать, но

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

может, если ЭРЭ системы это поддерживают.

решение2

Вам нужно удалить все до первого символа ␣->␣(не включая «стрелку») и после последнего ␣/(включая пробел и слеш).

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

$stringсейчас будет -> r1-ae0-2.

Те же две замены превратятся -> s7-Gi0-0-1:1-US / Fooв -> s7-Gi0-0-1:1-US.

решение3

Ответить на этот вопрос однозначно невозможно, не зная точного формата.каждыйсообщение принимает. Однако, как общий подход, вы можете распечатать определенные поля, используя cut:

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

Или вы можетераспечатать каждый n-й столбец, используяawk:

$ 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

Связанный контент