Как ссылаться на захваты в замене regex bash

Как включить регулярное выражение в замещающее выражение в BASH?

Нерабочий пример:

#!/bin/bash
name=joshua
echo ${name//[oa]/X\1}

Я ожидаю вывод jXoshuXa с заменой \1 на соответствующий символ.

На самом деле это не работает и выводит jX1shuX1.

Ответ 1

bash> name=joshua  
bash> echo $name | sed 's/\([oa]\)/X\1/g'  
jXoshuXa

Ответ 2

Возможно, не такой интуитивно понятный, как sed и, возможно, довольно неясный, но в духе полноты, в то время как BASH, вероятно, никогда не будет поддерживать переменные захвата вместо (по крайней мере, не в обычном порядке, поскольку круглые скобки используются для расширенного сопоставления с образцом), но это все еще возможно захватить шаблон при тестировании с помощью бинарного оператора =~ чтобы получить массив совпадений с именем BASH_REMATCH.

Возможен следующий пример:

#!/bin/bash
name='joshua'
[[ $name =~ ([ao].*)([oa]) ]] && \
    echo ${name/$BASH_REMATCH/X${BASH_REMATCH[1]}X${BASH_REMATCH[2]}}

Условное совпадение регулярного выражения ([ao].*)([oa]) фиксирует следующие значения в $BASH_REMATCH:

$ echo ${BASH_REMATCH[*]}
oshua oshu a

Если найдено, мы используем расширение ${parameter/pattern/string} чтобы найти шаблон oshua в параметре со значением joshua и заменить его комбинированной строкой Xoshu и Xa. Однако это работает только для нашего примера строки, потому что мы знаем, чего ожидать.

Для чего - то, что функции больше похожи на матч всех или глобальных регулярных выражений коллегами следующий пример жадный матч для любого неизмененном o или a вставления X от задней стенки к передней.

#/bin/bash
name='joshua'
while [[ $name =~ .*[^X]([oa]) ]]; do
    name=${name/$BASH_REMATCH/${BASH_REMATCH:0:-1}X${BASH_REMATCH[1]}}
done 
echo $name

Первая итерация изменяет $name на joshuXa и, наконец, на jXoshuXa прежде чем условие не jXoshuXa и цикл завершится. Этот пример работает аналогично виду выражения /(?<!X)([oa])/X\1/ котором предполагается, что нужно заботиться только о символах o или a префикса X

Выход для обоих примеров:

jXoshuXa

NJoy!

Ответ 3

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

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

Итак, ответ:

Если вы действительно не можете позволить запустить sed в подпроцессе, не используйте bash! Вместо этого используйте perl, цикл чтения-обновления-вывода будет в несколько раз быстрее, а разница в синтаксисе невелика. (Ну, вы не должны забывать точку с запятой.)

Я переключился на Perl, и был только один вопрос: поддержка Unicode не была доступна на одном из компьютеров, мне пришлось переустанавливать пакеты.