Извлечение строки в соответствии с шаблоном в bash-скрипте


17

В bash предположим, что у меня есть строка 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. Разумеется, расширение параметров в современных оболочках все еще прекрасно подходит.
Кодзиро

1
@kojiro, я понимаю, что ты имеешь в виду. Первоначальная формулировка состояла в том, чтобы продолжить ответ Джордана. Я обновил свой ответ.
Стефан Шазелас
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.