В заменяемой части всего 4 специальных символа: \ , & , новая строка и разделитель ( ref )
$ VAR='abc/def&ghi\foo
next line'
$ repl=$(sed -e 's/[&\\/]/\\&/g; s/$/\\/' -e '$s/\\$//' <<<"$VAR")
$ echo "$repl"
abc\/def\&ghi\\foo\
next line
$ echo ZYX | sed "s/Y/$repl/g"
Zabc/def&ghi\foo
next lineX
[your command] | paste -d '' - -
соединит последовательные строки.
Как только вы начнете использовать grep
XML, вы будете делать предположения о входных данных, и (почти наверняка )у вас больше не будет корректного вывода XML, так что иногда это не лучший путь вперед.
Тем не менее, путь наименьшего сопротивления часто включает в себя grep
, поэтому в зависимости от вашего XML (будет полезен хорошо -сформированный минимальный пример ), вы сможете использовать xmllint
с--xpath
(xmllint
>= 2.7.7 для --xpath
поддержка )вот так:
xmllint --xpath "//reference|//sourcefile" input.xml |
pcregrep -o "(<reference>.*?</sourcefile>)"
где xmllint
извлекает элементы, используя выражениеXPath , которое соответствует либо(|
как логическому «или» )интересующих вас элементов,(//
для выбора всех совпадающих элементов в любом месте ввод ). (не -не поддерживающий XML)pcregrep
(вместоegrep
)сопоставляет каждую пару элементов с группировкой и выводит каждую совпадающую группу по одной на -строку. Здесь следует отметить регулярное выражение .*?
, которое является PCRE не -жадным соответствием , поэтому оно соответствует минимальному объему текста между указанными тегами, а не всей строке. за один раз(xmllint --xpath...
выгружает все в одну строку ).
Использование grep немного "мошенничает", мы делаем предположения о входных данных, но xmllint
выполняет большую часть тяжелой работы. Такой подход может привести к проблемам с анализом в будущем, поскольку XML не является "обычным" , а регулярные выражения — не лучший инструмент для этой работы.
Аккуратный способ сделать это с помощью XMLStarlet:
xml select -t -m '//*' \
--if 'local-name()="reference"' -c. \
--elif 'local-name()="sourcefile"' -c. -o $'\n' input.xml
Это ищет все элементы (//*
), при совпадении <reference>
этот узел копируется в вывод (-c.
), иначе при совпадении <sourcefile>
этот узел копируется в вывод с дополнительной новой строкой вывода(-o $'\n'
).
Просто передайте данные наperl -pe 'chop if /^<reference>/'