Использование match для поиска подстрок в строках только с bash

Хотя я почти уверен, что это было рассмотрено, я не могу найти ничего конкретного по этому поводу. Продолжая свое путешествие по изучению bash, я продолжаю находить моменты, в которых я сбит с толку тем, почему все происходит именно так.

Поиск и замена или просто сопоставление подстрок в строках, скорее всего, является одним из первых действий, которые вы делаете при написании скриптов. Но пытаться придерживаться одного языка или набора инструментов сложно в bash, так как вы можете решить большую часть проблемы несколькими способами. Я делаю все возможное, чтобы оставаться с bash на как можно более низком уровне. Я столкнулся с загвоздкой, которую мне нужно, чтобы кто-то объяснил мне.

Выполнение поиска подстроки в bash с совпадением дает мне разные результаты в зависимости от используемого регулярного выражения, и я не уверен, почему.

#!/bin/bash
Stext="Hallo World"
echo `expr "$Stext" : '^\(.[a-z]*\)'` # Hallo
echo `expr "$Stext" : '.*World'`      # 11

Хотя оба ищут слово, я думаю, оба не возвращают то, что находят. Почему?


person Adesso    schedule 07.03.2012    source источник
comment
expr вообще не является функциональностью bash — это внешний инструмент, который не является частью оболочки. Следовательно, не гарантируется, что его поведение будет согласованным с данной версией bash при установке на разных платформах, за исключением минимальных гарантий, предоставляемых стандартом POSIX sh (гарантии, которые не обещают никакого синтаксиса регулярных выражений, кроме BRE). Кроме того, внешний вид означает, что он гораздо выполняется медленнее, требуя fork() для запуска подоболочки и exec() для замены этой оболочки внешним исполняемым файлом.   -  person Charles Duffy    schedule 08.08.2018
comment
Помимо того, что expr является внешним инструментом, вы повторяете результаты вызова команды в подоболочке, что делает ее вдвойне неэффективной. Эти вызовы должны быть развернуты, например. expr "$Stext" : '^\(.[a-z]*\)'. (см. superuser.com/questions/1352850/ для подробного объяснения)   -  person JakeRobb    schedule 22.07.2021


Ответы (4)


Оба выражения эквивалентны, разница заключается в используемом вами регулярном выражении:

$ echo `expr "$Stext" : '^\(.[a-z]*\)'`
Hallo
$ echo `expr "$Stext" : '^.[a-z]*'`
5
$ echo `expr "$Stext" : '\(.*World\)'`
Hallo World
$ echo `expr "$Stext" : '.*World'`
11

Как видите, скобки — это то, что имеет значение для возврата длины совпадения или самого совпадения.

Дополнительные примеры можно найти в главе 10 Расширенного руководства по написанию сценариев Bash. .

person jcollado    schedule 07.03.2012
comment
Спасибо за простое объяснение @jcollado :) Я использовал документы, которые вы предоставили, но почему-то не получил эту функциональность скобок. Руководство по Bash-Scripting не слишком легко усвоить. - person Adesso; 07.03.2012
comment
Поскольку этот вопрос касается bash, предпочтительнее использовать встроенное регулярное выражение как @kev предлагает вместо разветвления на /usr/bin/expr! - person F. Hauri; 28.02.2015

Вы можете использовать переменную BASH_REMATCH в bash, чтобы получить совпадающую строку:

$ Stext="Hallo World"
$ [[ $Stext =~ ^.[a-z]* ]] && echo $BASH_REMATCH
Hallo
$ [[ $Stext =~ ^(.[a-z]*) ]] && echo ${BASH_REMATCH[1]}
Hallo

Подстроки, соответствующие заключенным в скобки подвыражениям в регулярном выражении, сохраняются в переменной массива BASH_REMATCH. Элемент BASH_REMATCH с индексом 0 — это часть строки, соответствующая всему регулярному выражению. Элемент BASH_REMATCH с индексом n — это часть строки, соответствующая n-му подвыражению в скобках.

person kev    schedule 07.03.2012

Я сделал эту простую функцию:

match() {
    TRUE=1
    FALSE=0
    match_return=0
    echo $1 | grep $2 >/dev/null
    [ $? -eq 0 ] && match_return=$TRUE || match_return=$FALSE
}

Использование:

match Testing Test ; [ $match_return -eq 1 ] && echo "match!" || echo "nope"

весь код: https://gist.github.com/TeeBSD/5121b3711fad40a09455

person Antonio Feitosa    schedule 28.02.2015
comment
этот пост не имеет реального отношения к Вопросу или ответу. - person Adesso; 16.03.2015

Для быстрого поиска строк... Одним из вариантов является grep.
Если не найдено, возвращается пустое значение, в противном случае это совпадение:

found=`echo $big | grep -e $short`

if [ ! -z $found ]; then echo 'There is a match'; else echo 'No no'; fi
person Sergio Abreu    schedule 03.01.2017