У меня есть команда, чтобы найти все файлы .xml, содержащие <active>true</active>, имеющие <codePool>community</codePool> после этой строки в следующей строке.
grep -rzl '<active>true</active>.*<codePool>community</codePool>' --include='*.xml' --color=always
Теперь, как объединить это с sed заменить строку true внутри тега <active>... на строку false вдоль этих совпадающих строк?
Вы должны использовать инструменты синтаксического анализа XML для данных XML. xmlstarlet - хороший выбор. Регулярные выражения недостаточно эффективны (каноническая ссылка)
Если ваши данные выглядят так:
<root>
<foo>
<active>true</active>
<codePool>private</codePool>
</foo>
<foo>
<active>true</active>
<codePool>community</codePool>
</foo>
</root>
Затем
xmlstarlet ed --update '//active[.="true" and ../codePool="community"]' -v false file.xml
создает
<?xml version="1.0"?>
<root>
<foo>
<active>true</active>
<codePool>private</codePool>
</foo>
<foo>
<active>false</active>
<codePool>community</codePool>
</foo>
</root>
Вот awk-программа, которая делает то, что вы запрашиваете. Имейте в виду, что он хрупкий: если вход изменяется, этот код перестанет работать. Он просто использует простые операции с строкой.
awk '
BEGIN {
marker = "<codePool>community</codePool>"
srch = "<active>true</active>"
repl = "<active>false</active>"
}
index($0, marker) {
i = index(prev, srch)
if (i > 0)
prev = substr(prev, 1, i-1) repl substr(prev, i+length(srch))
}
{
if (prev) print prev
prev = $0
}
END {if (prev) print prev}
'