Заменить многострочную строку на sed - PullRequest
1 голос
/ 27 мая 2020
• 1000

Я пытаюсь написать небольшой bash скрипт, который заменит атрибуты для 'thing- c' предопределенным блоком. $ A1, $ a2 и $ a3 генерируются где-нибудь в более широком сценарии:

NEW_BLOCK="[thing-c]
attribute1=${a1}
attribute2=${a2}
attribute3=${a3}"

Я могу найти нужный блок с помощью sed вот так:

THING_BLOCK=$(sed -nr "/^\[thing-c\]/ { :l /^\s*[^#].*/ p; n; /^\[/ q; b l; }" ./myThingFile)

Я не уверен, что я спустился в кроличью нору или что с этим, и я ' Я почти уверен, что есть лучший способ сделать это.

Я хочу сделать то, что есть:

sed "s/${THING_BLOCK}/${NEW_BLOCK}/"

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

Есть ли способ выполнить такой многострочный поиск и замену с помощью sed (или лучше с помощью bash)

Ответы [ 3 ]

1 голос
/ 27 мая 2020

Еще один awk. Сохраните замену в file2 и:

$ awk -v RS="" '
NR==FNR {
    b=$0
    next
}
$1~/thing-c/ {
    $0=b
}
{
    print (++c==1?"":ORS) $0
}' file2 file1

Вывод:

[thing-a]
attribute1=foo
attribute2=bar
attribute3=foobar
attribute4=barfoo

[thing-b]
attribute1=dog
attribute3=foofoo
attribute4=castles

[thing-c]
attribute1=${a1}
attribute2=${a2}
attribute3=${a3}

[thing-d]
attribute1=123455
attribute2=dogs
attribute3=biscuits
attribute4=1234
1 голос
/ 27 мая 2020

Если вы хотите использовать sed (IMHO awk здесь лучше), у вас должны быть «хорошие» данные (никаких специальных символов, которые sed попытается обработать, и [ внутри блока thing-3) .
Я тестировал с

read -d '' -r NEW_BLOCK <<END
[thing-c]
attribute1=${a1}
attribute2=${a2}
attribute3=${a3}
END

Для моего решения мне сначала нужно заменить новые строки в $NEW_BLOCK двумя символами \n.

echo "This is the replacement string: ${NEW_BLOCK//$'\n'/\\n}"

С «многострочным» параметром «-z» вы можете сделать

sed -rz "s/\[thing-c\][^[]*/${NEW_BLOCK//$'\n'/\\n}\n\n/" myThingFile
1 голос
/ 27 мая 2020

Есть ли способ выполнить такой многострочный поиск и замену ...

Да, действительно есть способ лучше, хотя и с использованием awk:

awk -v blk="$NEW_BLOCK" -v RS= '{ORS = RT} $1 == "[thing-c]" {$0 = blk} 1' file

Используя -v RS=, мы используем пустой разделитель записей, который разделяет записи во входном файле на каждой новой строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...