Может ли sed делать обратные ссылки в шаблонах, определяющих диапазон?

Я пытаюсь использовать 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\}/— это два отдельных шаблона, и между ними не будут работать обратные ссылки? Если да, то как мне это сделать?

3
24.06.2020, 10:44
2 ответа

Вы правы :Хотя обратные ссылки определены в основных регулярных выражениях(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
}
3
18.03.2021, 23:25

Обратные -ссылки можно использовать в /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удаляет все после первой закрывающей скобки с соответствующим отступом. Эти последние две команды нужны только тогда, когда есть несколько блоков конфигурации на том же уровне отступа, что и интересующий.

2
18.03.2021, 23:25

Теги

Похожие вопросы