Извлечение строк между двумя шаблонами и удаление между строк с условием if - PullRequest
1 голос
/ 25 июня 2019

У меня есть файл со следующим содержанием.Я пытаюсь извлечь блок с совпадающими начальными и конечными шаблонами, между которыми я хочу исключить блок, который имеет несовпадающий числовой идентификатор (возможно, шаблон).Здесь кроме [001] должен быть исключен.002 может быть неизвестно.Итак, я хочу, чтобы блоки совпадали только с [001].

Файл содержит,

    text [001] start
    line 1
    line 2
    text [002] mid start
    line 3     
    line 4
    text [002] mid end
    line 5
    line 6
    text [001] end

Мне нужен блок с исключением несоответствующего блока числового идентификатора [002].

    text [001] start
    line 1
    line 2
    line 5
    line 6
    text [001] end

Я не смог получить четкое разъяснение в интернете по этой проблеме.Кто-нибудь может помочь с этим, awk или sed решением?

Чтобы получить блок с начальным и конечным шаблоном, я пытаюсь с

   awk '/[001]/ && /start/, /001/ && /end/' File

Ответы [ 5 ]

1 голос
/ 25 июня 2019

Предполагая, что ваши блоки вложены на любую глубину и никогда не перекрываются:

$ cat tst.awk
BEGIN { tgtId="001" }

match($0,/\[[0-9]+\]/) {
    id = substr($0,RSTART+1,RLENGTH-2)
    state = $NF
}

state == "start"  { isTgtBlock[++depth] = (id == tgtId ? 1 : 0) }

isTgtBlock[depth] { print }

state == "end"    { --depth }

{ id = state = "" }

$ awk -f tst.awk file
    text [001] start
    line 1
    line 2
    line 5
    line 6
    text [001] end
1 голос
/ 25 июня 2019

Это awk может сделать.Вам может понадобиться настроить триггер, чтобы он работал с вашими данными:

awk '/\[001\] start/{f=1} /\[002\] .* start/{f=0} f;  /\[001\] end/{f=0}  /\[002\] .* end/{f=1}' file
    text [001] start
    line 1
    line 2
    line 5
    line 6
    text [001] end

Более читабельный

awk '
    /\[001\].*start/ {f=1}
    /\[002\].*start/ {f=0} 
    f;  
    /\[001\].*end/ {f=0}
    /\[002\].*end/ {f=1}
    ' file

Просто измените код триггера, чтобы отразить истинные данные.

1 голос
/ 25 июня 2019

Предположим, что мы используем переменные b1, если мы находимся в блоке 1, и b2, если мы находимся в блоке 2:

awk '/001/ && /start/ { b1=1 }
     /002/ && /start/ { b2=1 }
     (b1 && !b2)
     /002/ && /end/   { b2=0 }
     /001/ && /end/   { b1=0 }' file

Выражения диапазона удобны, но процитировать Ed Morton : Никогда не используйте выражения диапазона (например, /start/,/end/), поскольку они делают тривиальные задачи очень короткими, а затем требуют дублирующих условий или полного переписывания для крошечного изменения требований.

1 голос
/ 25 июня 2019

Используйте sed или Perl:

sed '/001.*start/,/001.*end/!d;/002.*start/,/002.*end/d'

perl -ne 'print if /001.*start/ .. /001.*end/
                and not /002.*start/ .. /002.*end/'

Использование предварительных утверждений может легко сделать динамический исключенный тег:

perl -ne 'print if /001.*start/ .. /001.*end/
                and not /text \[(?!001).*start/ .. /text \[(?!001).*end/'
0 голосов
/ 26 июня 2019

Это может сработать для вас (GNU sed):

sed -n '/\[001\]/,/\[001\]/{/\[002\]/,/\[002\]/!p}' file

Печатать только строки между [001] разделителями и исключать эти строки между [002] разделителями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...