Нужен grep / awk / gawk, чтобы вернуть весь раздел, несмотря на разрыв строки - PullRequest
0 голосов
/ 25 апреля 2018

У меня следующая проблема ... У меня есть файл, похожий на этот:

2018-04-25: line1
2018-04-25: line2
        this is another line
        I'm a line
2018-04-25: line3
2018-04-25: line4

Если я запущу: grep 'this' test.log результат будетбыть:

    this is another line

но мне нужен результат:

2018-04-25: line2
        this is another line
        I'm a line

, потому что «это другая строка» на самом деле является частью той же записи, единственная проблема в том, что у нас естьтам есть строка разрыва, и мне нужен мой grep, чтобы игнорировать эту строку разрыва.

  • grep -C 1 'this' test.log
  • grep -B 1 'this' test.log

на самом деле не вариант, потому что между началом записи и концом может быть больше строк / разрывных строк.

Ответы [ 7 ]

0 голосов
/ 26 апреля 2018

grep пробелы, начинающиеся со строки -B 1:

$ grep -B 1 "^ " file
2018-04-25: line2
        this is another line
        I'm a line

Если места недостаточно: grep -B 1 -v "^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}:" file

0 голосов
/ 27 апреля 2018

От совпадения регулярного выражения до другого регулярного выражения:

awk '/line2/{f=1} f;/I\47m a line/{f=0}' file 

2018-04-25: line2
        this is another line
        I'm a line
0 голосов
/ 25 апреля 2018

Просто для завершения, мы можем сделать это также с sed более загадочно:

 sed -n '/[-0-9]\{10\}:/{x;/this/p;d};H;${x;/this/p}' <file>

или короче:

 sed -n '/[-0-9]\{10\}:/ba;H;$!b;:a;x;/this/p' <file>

Чтобы понять это, вам нужно знатьу этого sed есть два воспоминания.В шаблонном пространстве вы выполняете все операции, а удерживающее пространство - это долговременная память.Идея состоит в том, чтобы создать запись в поле для хранения , добавив каждую строку с H.Однако, если строка файла (т. Е. пробел ) содержит дату, проверьте, что находится в пробел , и распечатайте при необходимости.Замена обоих пробелов производится с помощью x.

Шаг за шагом:

sed -n '                       # -n suppress automatic printing of pattern space
        /[-0-9]\{10\}:/ba;     # did we find a date? if so goto label 'a'
        H;                     # append the line to the hold space
        $!b;                   # did we reach EOF? if not, go to the beginning
        :a;                    # create label 'a'
        x;/this/p              # you found a date or hit the EOF
                               # swap the patterns with 'x'
                               # check if it contains /this/
                               # if so print
        ' <file>
0 голосов
/ 25 апреля 2018

Другая многострочная версия awk:

#!/usr/bin/awk -f    

# When the line is starting with the time string
# a new record is starting...
/^[[:digit:]]{4}(-[[:digit:]]{2}){2}/ {
    # Check if the (b)uffer matches /this/
    if(b~/this/)
       # ... and print it in that case
       print b

    # Empty the buffer in any case
    b="" 
}

# Append each line to the buffer
{b=b""ORS""$0}

Должно работать с любой версией awk.

0 голосов
/ 25 апреля 2018

Для данного образца это будет работать

$ gawk -v ORS= -v RS='2018-' '/this/{print RS $0}' ip.txt
2018-04-25: line2
        this is another line
        I'm a line
  • -v ORS= очистить разделитель выходных записей
  • -v RS='2018-' установить 2018- в качестве разделителя входных записей (при условии, что год одинаков для всех записей)
  • /this/{print RS $0}, если запись содержит this, распечатать разделитель записей и содержание записи
0 голосов
/ 25 апреля 2018

Вот один из способов использования GNU awk: дата в начале строки является разделителем записей. Для записи, содержащей шаблон, выведите предыдущий разделитель записей и текущую запись.

gawk -v RS='(^|\n)[0-9-]{10}' '
    /this/ {sub(/^\n/, "", prev_RT); print prev_RT $0} 
    {prev_RT = RT}
' file

Или, более просто

awk '
    function printif() {if (record ~ /this/) print record}
    /^[0-9-]{10}/ {printif(); record = ""} 
    {record = (record ? record "\n" : "") $0} 
    END {printif()}
' file
0 голосов
/ 25 апреля 2018

Если это ввод:

2018-04-25: line1
2018-04-25: line2
        this is another line
        I'm a line
2018-04-25: line3
2018-04-25: line4

Вы можете использовать: grep -A2 line2 file.log, и он вернется:

2018-04-25: line2
        this is another line
        I'm a line

-A означает after-context, от человека:

-A num, --after-context=num
         Print num lines of trailing context after each match. 

Или вы можете использовать сочетание -B и -A, если в качестве шаблона используется this, например:

grep -B1 -A1 this file.log
...