2015-01-12 2 views
1

Я пытаюсь флаг все внутри тег цвета и заменить его чем-то другое, например:SED заменить между двумя строками подстановочных

I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house. 

в

I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house. 

Вот что я имею пробовал:

sample='I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house.' 
replace='foobar' 
sample=$(echo $sample| sed "s/\[color=blue\].*\[\/color\]/\[color=blue\]\[b\]$replace\[\/b\]\[\/color\]/g") 

Который получает меня:

I have a [color=blue][b]foobar[/b][/color] in my house. 

Любая идея о том, как сделать sed nongreedy в этом случае?

ответ

1

Просто замените .* на [^[]* (любой символ, кроме левого кронштейна). То есть:

"s/\[color=blue\][^[]*\[\/color\]/\[color=blue\]\[b\]$replace\[\/b\]\[\/color\]/g" 
1

sed всегда жадный. Вы можете обойти это, тщательно выбирая регулярное выражение. Приведенный ниже пример идентичен с вашим исключением того, что .* был заменен [^[]* (что означает, что все, кроме [):

$ echo $sample| sed "s/\[color=blue\][^[]*\[\/color\]/\[color=blue\]\[b\]$replace\[\/b\]\[\/color\]/g" 
I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house. 

Для действительно нежадным регулярных выражений, попробуйте Perl или Python.

0
sed 's#\(\[color=[[:alpha:]]*\]\)[[:alnum:]]*\(\[/color\)#\1[b]foobar[/b]\2#g' 

Пример

echo 'I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house.'|sed 's#\(\[color=[[:alpha:]]*\]\)[[:alnum:]]*\(\[/color\)#\1[b]\2#g' 

выход

I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house. 
0
sed -r 's/(\[color=[a-z]*\])[a-z]*(\[\/color\])/\1[b]foobar[\/b]\2/g' File 

или

sed 's/\(\[color=[a-z]*\]\)[a-z]*\(\[\/color\]\)/\1[b]foobar[\/b]\2/g' File 

Е xplanation: Здесь мы ищем модели 1. [color=any small letter sequence] с последующих 2. any small letter sequence с последующих 3. [/color] и групповые моделями 1 and 3 с использованием ( и ). Тогда мы выполняем замены. Мы сохраняем 1st and 2nd groups (используя \1 и \2), но заменим содержимое между первой и второй группами [b]foobar[/b].

+0

Этот ответ был помечен как низкого качества из-за его длины и содержания. Не могли бы вы дать объяснение для своего кода? – BMW

+0

@BMW: сделано! :-) –

+0

@ A.M.D вам не нужно обратная косая черта в замене. –

0

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

Использование карата внутри кронштейнов [^ABC] эффективно означает, что не следует.

Так что, используя это с помощью asterix *, он будет соответствовать только одному из следующих символов.


Например

[^[]* 

будет соответствовать все до следующего [ кронштейна

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

В любом случае, вот команда, которая должна работать.

sed 's/\(\[color[^]]*\]\)[^[]*\(\[\/color\]\)/\1[b]foobar\[b]\2/g' 
0

sed всегда будет жадным. Вы можете использовать perl, если вы строго хотите нежадным вариант:

$ echo $test 
I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house. 

$ perl -pne 's/(\[color=[a-zA-Z]*\])(.*?)(\[\/color\])/$1\[b\]foobar\[\/b\]$3/g' <<< "$test" 
I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house. 

Я думаю, вы можете интерпретировать большинство регулярных выражений здесь, за исключением крошечного изменения синтаксиса, за исключением:
(.*?) вместо (.*) диктует, что матч должен быть неживым.
Если вы пропустите ? после .*, вот вывод, который вы должны получать в настоящее время:

$ perl -pne 's/(\[color=[a-zA-Z]*\])(.*)(\[\/color\])/$1\[b\]foobar\[\/b\]$3/g' <<< "$test" 
I have a [color=blue][b]foobar[/b][/color] in my house. 
Смежные вопросы