Чи підтримує bash зворотні посилання при розширенні параметрів?


15

У мене є ім'я змінної , 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"для цього. Чи є кращий спосіб зробити це? Чи можливо це зробити і при розширенні параметра?

Відповіді:


20

ksh93і zshмати підтримку зворотного посилання (або, точніше, 1 , посилань на захоплення груп в заміну) всередині ${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Сторінка man також згадує, що майбутні версії підтримуватимуть її ${KSH_MATCH[1]}для першої групи захоплення. Доступно ще не 2017-2014).

Однак, bashви можете:

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

Що краще, оскільки він перевіряє, що модель знайдена спочатку.

Якщо регекс-файли вашої системи підтримують \s/ \S, ви також можете зробити:

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

З zsh, ви можете отримати повну потужність PCREs з:

$ 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 ]]використовує Eres.

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

не збігатиметься, але

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

може, якщо ERE системи підтримують його.


9

Ви хочете видалити все до першої ␣->␣(не включаючи стрілку) та після останньої ␣/(включаючи пробіл та косу рису).

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.