Витягнення рядка, за зразком, у скрипті bash


17

Скажімо, в басі, припустимо, що у мене є рядок strname:

strname="ph7go04325r"

Я хотів би витягнути символи між першим "3" символом і останнім "r" символом strname, зберігаючи результат у рядку strresult. У наведеному вище прикладі отримано strresult:

strresult="25"

Перший "3"символ не обов'язково знаходиться в положенні рядка 8 дюйма strname; то ж саме, останній "r"є НЕ обов'язково в струнному положенні 11. Таким чином, обидва з наступних рядків strnameповинні давати strresult="25":

strname="ph11go04325raa"
strname="325r"
strname="rgo04325raa"

Також, strname=ph12go04330raa"слід поступатися strresult="30".

Я новачок в сценаріїх bash, і я не знаю, з чого почати робити відповідність рядків, як це. Чи є у вас якісь пропозиції?

Відповіді:


28

Ви можете використовувати регулярний вираз в bash (3.0 або вище), щоб досягти цього:

if [[ $strname =~ 3(.+)r ]]; then
    strresult=${BASH_REMATCH[1]}
else
    echo "unable to parse string $strname"
fi

У bash групи захоплення з регулярного виразу розміщуються в спеціальному масиві BASH_REMATCH. Елемент 0 містить всю відповідність, а 1 містить відповідність для першої групи захоплення.


10

У стандартному shсинтаксисі (так би працювало з будь-якою версією bashабо будь-якою іншою оболонкою, сумісною з POSIX), ви зробите:

case $strname in
  (*3*r*) 
    strresult=${strname#*3}
    strresult=${strresult%r*};;
  (*)
    printf >&2 '%s\n' "Unable to parse string $strname"
esac

Дивіться також старе exprрішення, яке буде працювати навіть у 35-річних Unices:

expr "x$strname" : 'x[^3]*3\(.*\)r'

Стара вигадка з того expr, що якщо збіг не вдасться, ви отримуєте ненульовий статус виходу (добре), але ви також отримуєте ненульовий статус виходу, якщо повернені рядки дорівнюють 0 (наприклад, з strname=zz300rzz).


Я думаю, що ваше фразування невірно означає, що це можна зробити лише зі старими версіями bash. Розширення параметрів, звичайно, все ще є прекрасним підходом у сучасних оболонках.
kojiro

1
@kojiro, я бачу, що ти маєш на увазі. Початковою формулюванням було відповідати на відповідь Джордана. Я оновив свою відповідь.
Stéphane Chazelas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.