Я пытаюсь использовать sed
для извлечения из длинного файла (конфигурация Junos) блока конфигурации, разделенного фигурными скобками:
group foo {
command;
setting {
value;
}
command;
}
Хитрость заключается в том, чтобы остановиться на }
с таким же отступом, как и первая строка.
Я научился использовать sed
для сопоставления одного шаблона с другими попробовал следующее:
$ sed -rn '/^( *)group foo/,/^\1\}/p' config.txt
sed: -e expression #1, char 41: Invalid back reference
Проблема в том, что /^( *)group foo/
и /^\1\}/
— это два отдельных шаблона, и между ними не будут работать обратные ссылки? Если да, то как мне это сделать?
Вы правы :Хотя обратные ссылки определены в основных регулярных выражениях(BRE)(и поскольку каждый адрес sed является BRE , он поддерживает обратные -ссылки ), обратная ссылка не может получить группу захвата, определенную в другом BRE. Таким образом, группа захвата по адресу /^( *)group foo/
не может быть получена по другому адресу /^\1\}/
.
Это test.awk
делает это путем подсчета открывающих и закрывающих фигурных скобок:
brk && /\{/{brk++} #Increment brk if brk is not zero and line contains {
brk && /\}/{brk--} #Decrement brk if brk is not zero and line contains }
/^[[:blank:]]*group foo \{/{brk=1;prt=1} #Set brk and prt if match initial pattern
prt #Print line if prt is set
!brk && prt{prt=0} #If brk is zero and prt is not, set prt=0
$ cat file
foo bar
foo bar2
}
group foo {
command;
setting {
value;
}
command;
}
dri {
}
end
$ awk -f test.awk file
group foo {
command;
setting {
value;
}
command;
}
Еще один менее элегантный вариант, основанный на подсчете пустых мест, как и в вашей попытке. Он ломается, если в отступе есть вкладки.
/^ *group foo \{/{
match($0,/^ */) #Sets RLENGTH to the length in characters of the matched string
i=RLENGTH
}
i #If i is set, the current line is printed
i&&/^ *\}$/{
match($0,/^ */) #Again, sets RLENGTH to the length of the matched string
if(RLENGTH==i){i=0} #If the value is equal to the one from group foo line, unset i
}
Обратные -ссылки можно использовать в /pattern/
, но они не запоминаются от одного такого выражения к другому.
В sed есть много решений, например (с использованием GNU sed):
sed -rz 's@.*\n(( *)group foo.*\2}).*@\1@;s@^(( *).*)@\1\2@;s@(\n( *)}).*\2$@\1\n@' config.txt
Флаг -z
используется для загрузки всей конфигурации в пространство шаблонов. Первый s
удаляет все до начала group foo
и после последней закрывающей скобки (жадно *)с соответствующим отступом.
Второй s
копирует этот отступ до конца. Последний s
удаляет все после первой закрывающей скобки с соответствующим отступом. Эти последние две команды нужны только тогда, когда есть несколько блоков конфигурации на том же уровне отступа, что и интересующий.