Это один из способов использования GNU awk для RS и RT с несколькими символами:
$ awk -v RS='%]' -v ORS= '{print gensub(/.*(\n[^\n]*\[%)/,"\\1",1) RT}' file
[% FOREACH selection = selections -%]
case SELECTION_ID_[% SELECTION_NAME %]
const [% selectionType %]& source = this->[% selectionName %]
[% END -%]
[% INCLUDE attributeSearchBlock
tree=attributeSearchTree depth=0
visit='ReturnAttributeInfo' name='name' nameLength='nameLength' -%]
, а вот другой способ с RS и FPAT с несколькими символами:
$ cat tst.awk
BEGIN {
RS = "^$"
FPAT = "[^\n]*{[^{}]*}"
}
{
gsub(/@/,"@A"); gsub(/{/,"@B"); gsub(/}/,"@C")
gsub(/\[%/,"{")
gsub(/%\]/,"}")
for (i=1; i<=NF; i++) {
str = $i
gsub(/}/,"%]",str)
gsub(/{/,"[%",str)
gsub(/@C/,"}",str); gsub(/@B/,"{",str) gsub(/@A/,"@",str)
print str
}
}
$ awk -f tst.awk file
[% FOREACH selection = selections -%]
case SELECTION_ID_[% SELECTION_NAME %]
const [% selectionType %]& source = this->[% selectionName %]
[% END -%]
[% INCLUDE attributeSearchBlock
tree=attributeSearchTree depth=0
visit='ReturnAttributeInfo' name='name' nameLength='nameLength' -%]
Второй сценарийдемонстрирует общую идиому при использовании такого инструмента, как awk или sed, который поддерживает только жадные совпадения, но вам нужно сопоставлять текст между многосимвольными строками, то есть преобразовывать эти многосимвольные строки-разделители в отдельные символы, чтобы затем можно было использовать класс отрицанных символовмежду ними.
Таким образом, в приведенном выше примере:
gsub(/@/,"@A"); gsub(/{/,"@B"); gsub(/}/,"@C")
Я конвертирую все @
с в @A
с, чтобы освободить символ @
, а затем конвертирую все {
s до @B
s (теперь это строка, которую, как мы ЗНАЕМ, на входе нет, поскольку мы ставим A после каждого @), а затем преобразуем все }
s в @C
s, обеспечивая тем самымна входе нет символов {
или }
, поэтому мы освобождаем их для использования в качестве разделителей регулярных выражений.Теперь я могу сделать:
gsub(/\[%/,"{")
gsub(/%\]/,"}")
для преобразования вашего реального разделителя строк в символов , чтобы я мог использовать их отрицание в регулярном выражении, чтобы соответствовать строкемежду этими разделителями:
FPAT = "{[^{}]*}"
В GNU awk назначение FPAT таким образом автоматически сохраняет совпадающие строки в $ 1, $ 2 и т. д., поэтому мне просто нужно разматывать вышеуказанные замены перед печатью каждого поля, следовательно:
gsub(/}/,"%]",str)
gsub(/{/,"[%",str)
gsub(/@C/,"}",str); gsub(/@B/,"{",str) gsub(/@A/,"@",str)
Эквивалент 2-го сценария выше для любого POSIX awk:
$ cat tst.awk
{ rec = (NR>1 ? rec ORS : "") $0 }
END {
$0 = rec
FPAT = "[^\n]*[{][^{}]*[}]"
gsub(/@/,"@A"); gsub(/[{]/,"@B"); gsub(/[}]/,"@C")
gsub(/\[%/,"{")
gsub(/%\]/,"}")
while ( match($0,FPAT) ) {
str = substr($0,RSTART,RLENGTH)
$0 = substr($0,RSTART+RLENGTH)
gsub(/[}]/,"%]",str)
gsub(/[{]/,"[%",str)
gsub(/@C/,"}",str); gsub(/@B/,"{",str) gsub(/@A/,"@",str)
print str
}
}
$ awk -f tst.awk file
[% FOREACH selection = selections -%]
case SELECTION_ID_[% SELECTION_NAME %]
const [% selectionType %]& source = this->[% selectionName %]
[% END -%]
[% INCLUDE attributeSearchBlock
tree=attributeSearchTree depth=0
visit='ReturnAttributeInfo' name='name' nameLength='nameLength' -%]