Выбор линий между шаблонами маркеров, где один шаблон может встречаться дважды - PullRequest
2 голосов
/ 19 марта 2020

Если у меня есть файл, содержащий некоторые текстовые данные, такие как

PATTERN1
TEXT1
PATTERN1
TEXT2
PATTERN2

Как мне выбрать данные TEXT2 из этого файла, я знаю PATTERN1 и PATTERN2? Я попытался использовать awk, как упомянуто здесь , но он печатает как TEXT1 и TEXT2.

Ответы [ 5 ]

2 голосов
/ 19 марта 2020

Если TEXT2 всегда окружен PATTERN1 и PATTERN2, вы можете использовать grep:

grep -B2 "PATTERN2" file | grep -A1 "PATTERN1" | grep -v "PATTERN1"
  • grep -B2 "PATTERN2" -> захватить PATTERN2 и предыдущие 2 строки
  • grep -A1 "PATTERN1" -> из этих трех строк возьмите PATTERN1 и строку после
  • grep -v "PATTERN1" -> избавьтесь от строки / строк, содержащих PATTERN1, и у вас останется TEXT2
2 голосов
/ 19 марта 2020
$ awk '
inBlock {
    if ( /PATTERN2/ ) {
        printf "%s", block
        inBlock = 0
    } else {
        block = block $0 ORS
    }
}
/PATTERN1/ {
    inBlock = 1
    block = ""
}
' file
TEXT2
1 голос
/ 19 марта 2020

Если PATTERN2 может происходить несколько раз, это извлекает только внутренний текст:

sed '/PATTERN1/h;//!H;/PATTERN2/!d;//{x;/PATTERN1/!d}'

Если PATTERN2 может встречаться только один раз, вы можете использовать такой скрипт sed:

sed -n '/PATTERN1/h;//!H;/PATTERN2/{x;p}' input_file.txt

или:

sed '/PATTERN1/h;//!H;/PATTERN2/!d;//x'

Вы можете перевернуть строки, затем использовать sed с 2 адресами и снова перевернуть строки:

tac input_file.txt | sed -n '/PATTERN2/,/PATTERN1/p' | tac

С помощью sed -z мы можем удалить все в перед и после шаблонов, так как регулярное выражение является жадным:

sed -z 's/.*\(PATTERN1\n\)/\1/;s/\(PATTERN2\n\).*/\1/g'
1 голос
/ 19 марта 2020

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

sed '/PATTERN1/{z;x;d};/PATTERN2/!{H;d};g;s/.//p;d' file

Если текущая строка содержит PATTERN1, очистите строку и удалите пробел удержания (HS).

Если текущая строка не содержит PATTERN2, добавьте ее в HS и удалите строку.

Если текущая строка содержит PATTERN2, замените ее содержимым HS, удалите первый символ (который будет введена новая строка), напечатайте результат и удалите строку.

Альтернатива:

sed -En '/PATTERN1/{:a;/PATTERN1/z;N;/PATTERN2/!ba;s/.(.*)\n.*/\1/p}' file

Первое решение предполагает, что файл будет содержать PATTERN1 и PATTERN2, второй нет.

0 голосов
/ 19 марта 2020

Perl на помощь!

perl -ne 'print(@buffer), $inside = @buffer = () if /PATTERN2/;
          push @buffer, $_ if $inside;
          @buffer = (), $inside = 1 if /PATTERN1/;
' -- file.txt

Мы сохраняем массив строк для вывода в @buffer. Мы также сохраняем флаг $ внутри, который установлен в true, если мы встретили PATTERN1, но еще не PATTERN2.

  • Если мы видим PATTERN2, мы печатаем буфер и очищаем флаг.
  • Если мы внутри, мы помним текущую строку.
  • Если мы видим PATTERN1, независимо от того, видели ли мы его раньше или нет, мы очищаем буфер и устанавливаем флаг.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...