Сохранять соответствие шаблону в расширении параметров оболочки

Вопрос или проблема

Я могу удалить шаблон в переменной bash, используя ${variable##pattern} (лидирующий) или ${variable%%pattern} (трейлинг).

Но я не могу найти способ только на bash, чтобы сохранить шаблон и выбросить остальное.

Я знаю, что есть решения с использованием sed, awk или grep, но я хочу знать, есть ли разумно эффективное решение только на bash, которое я упускаю?

PS: Это не просто праздный вопрос. Исходная проблема в том, что я хочу обработать файлы, имя которых содержит шаблон (технически, '[A-Z]+([A-Z])-[0-9][0-9]+([0-9])': заглавные буквы, за которыми следует дефис и цифры) и я хочу использовать тот же шаблон, чтобы перечислить файлы и извлечь соответствующую строку для дальнейшей обработки.

${var%"${var##pattern}"}
${var#"${var%%pattern}"}

Пример:

$ k='ab*10cd20ef*'
$ echo "${k%"${k##*[0-9]}"}"
ab*10cd20
$ echo "${k#"${k%%[0-9]*}"}"
10cd20ef*

Обратите внимание, что кавычки важны, чтобы предотвратить интерпретацию оболочки расширений как шаблона. Попробуйте echo "${k#${k%%[0-9]*}}", чтобы увидеть, что это приведет к неправильному результату.

В Bash вы также можете использовать регулярные выражения:

#!/bin/bash
re="[A-Z][A-Z]+-[0-9][0-9][0-9]+"
file=foo-BAR-1234.txt
if [[ $file =~ $re ]]; then
    echo "имя файла '$file' совпадает, совпадающая часть '${BASH_REMATCH[0]}'"
fi

С file=foo-BAR-1234.txt это совпадает с частью BAR-1234 и выводит соответствующим образом. Вы также можете использовать скобки в регулярном выражении, чтобы захватить часть шаблона, они будут доступны в ${BASH_REMATCH[1]} и т. д.

Конечно, обратите внимание, что формат для регулярных выражений отличается от формата расширенных гло́бов Bash/Ksh: вместо +([abc]) вам нужно использовать [abc]+ или ([abc])+, при этом скобки являются необязательными, когда звездочка применяется только к одной группе скобок. То же самое касается * и ?. Также вы можете записать, например, [0-9]{3,}, для трех и более цифр.

Получение только совпадения шабона регулярного выражения с помощью одного расширения переменной:

Немного поздно, но может быть полезно для кого-то еще. Пример: Я создал это для извлечения нумерации эпизодов из текста телесериала. (что является регулярным выражением с неизвестными числами)

Следующий код содержит некоторые поясняющие комментарии.

#!/bin/bash

#Это для расширенного гло́бирования
shopt -s extglob

#Получение только совпадения шаблона регулярного выражения с помощью расширения переменной
Var="Текст перед совпадением_S02E12_Текст после совпадения"

#Мы хотим только шаблон из эпизода телесериала
MatchPattern="S[0-9][0-9]E[0-9][0-9]"

OnlyTheMatch="${Var//@(${Var//@($MatchPattern)*}|${Var//*@($MatchPattern)})/}"

echo "${OnlyTheMatch}" > Output_OnlyTheMatchPattern.txt

#Сброс расширенного гло́бирования
shopt -u extglob

#Это делает следующее:
#Мы "заменяем" текст до и после на "ничто"  ${Var//match/}
#(и тем самым удаляем их)
#${Var//match/} может удалить только одно совпадение, но мы хотим удалить несколько (текст до И после)
#Чтобы использовать несколько шаблонов совпадений, мы должны поместить их в @(..|..) разделенные вертикальными чертами '|'
#OnlyTheMatch="${Var//@(TextBeforeMatch|TextAfterMatch)/}"
#Текст перед совпадением можно найти с помощью расширения переменной: ${Var//@($MatchPattern)*}
#Текст после совпадения также можно найти с помощью расширения переменной: ${Var//*@($MatchPattern)}
#И эти переменные могут обе быть записаны в @(..|..) разделенные вертикальными чертами '|'
#Вместе создавая одно расширение переменной для получения только совпадающего шаблона.

Может быть, это близко к тому, что вы ищете.

Ответ или решение

Как сохранить совпадение шаблона в Bash-расширении переменной

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

Введение в расширение переменных Bash

Расширение переменных в Bash предоставляет удобные методы для манипуляции строками. С помощью конструкций вроде ${variable##pattern} и ${variable%%pattern} мы можем удалять части строки. Однако чтобы сохранить совпадение шаблона, но удалить остальную часть строки, приходится использовать более сложные конструкции.

Сохранение совпадения шаблона с использованием расширения переменных

Для решения вашей задачи можно воспользоваться следующими подходами:

  1. Удаление всего, кроме совпадения: Можно использовать механизм на основе специальных символов и переменного расширения, чтобы отсеять ненужные части.
#!/bin/bash

Var="Text before match_S02E12_Text after match"
MatchPattern="S[0-9][0-9]E[0-9][0-9]"

# Включаем расширенные глобусы
shopt -s extglob

# Сохраняем совпадение
OnlyTheMatch="${Var//@(${Var//@($MatchPattern)*}|${Var//*@($MatchPattern)})/}"

# Проверяем результат
echo "${OnlyTheMatch}"

В этом примере мы используем механизм @(pattern) для определения всех частей строки, которые не соответствуют заданному шаблону, и удаляем их.

Использование базовых регулярных выражений в bash

Помимо методов расширения, полные регулярные выражения также могут быть использованы с помощью [[ ]].. Например:

#!/bin/bash
re="([A-Z]+-[0-9]+)"
file="foo-BAR-1234.txt"

if [[ $file =~ $re ]]; then
    echo "Совпадение в имени файла: '${BASH_REMATCH[0]}'"
fi

Этот подход позволяет находить и выводить совпадение с шаблоном, где используется встроенная поддержка регулярных выражений.

Подходы к обработке имен файлов

Если вы хотите извлечь совпадение из имени файла, содержащего буквы и цифры, приведенное решение можно адаптировать и расширить:

#!/bin/bash

# Задать регулярное выражение
regex="([A-Z]+-[0-9]+)"
for file in *.txt; do
    if [[ $file =~ $regex ]]; then
        echo "Найдено совпадение в файле '$file': '${BASH_REMATCH[0]}'"
    fi
done

Заключение

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

Каждое из предложенных решений подходит для различных сценариев, будь то работа с переменными или обработка имен файлов. Исследуйте, адаптируйте и используйте тот метод, который наилучшим образом соответствует вашим требованиям.

Оцените материал
Добавить комментарий

Капча загружается...