В sed или awk, как мне обрабатывать разделители записей, которые *могут* занимать несколько строк?

Мой файл журнала:

 Wed Nov 12 blah blah blah blah cat1
 Wed Nov 12 blah blah blah blah
 Wed Nov 12 blah blah blah blah 
 Wed Nov 12 blah blah blah blah cat2
     more blah blah
     even more blah blah
 Wed Nov 12 blah blah blah blah cat3
 Wed Nov 12 blah blah blah blah cat4

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

то есть я хочу, чтобы мой анализ производил:

 Wed Nov 12 blah blah blah blah cat1
 Wed Nov 12 blah blah blah blah cat2
     more blah blah
     even more blah blah
 Wed Nov 12 blah blah blah blah cat3
 Wed Nov 12 blah blah blah blah cat4

person Aaron Fi    schedule 21.11.2008    source источник
comment
Как тогда определить конец логической строки? Будут ли строки, начинающиеся с пустой строки, автоматически считаться продолжением строки над ней?   -  person Paul Tomblin    schedule 22.11.2008


Ответы (4)


если вы скажете, что каждая строка, начинающаяся с пробела, является продолжением следующей, это легко сделать с помощью (g)awk (это из моей памяти, поэтому, возможно, она содержит некоторые незначительные опечатки и для лучшей читаемости с некоторыми дополнительными разрывами строк):

awk " BEGIN { multiline = 0;} 
      ! /^ / { if (whatever) 
                 { print; multiline = 1;} 
               else 
                 multiline = 0; 
             } 
        /^ / {if (multiline == 1) 
                 print;
             } 
     " 
      yourfile

где whatever — ваша проверка, должен ли произойти ваш вывод (например, для кота).

person flolo    schedule 21.11.2008

Предполагая, что ваш файл журнала не содержит управляющих символов '\01' и '\02' и что непрерывная строка начинается ровно с четырех пробелов, может работать следующее:

c1=`echo -en '\01'`
c2=`echo -en '\02'`
cat logfile | tr '\n' $c1 | sed "s/$c1    /$c2/g" | sed "s/$c1/\n/g" | grep cat | sed "s/$c2/\n    /g"

Объяснение: это заменяет каждую новую строку на ASCII 1 (управляющий символ, который никогда не должен появляться в файле журнала), а каждую последовательность «новая строка-пробел-пробел-пробел-пробел» на ASCII 2 (еще один управляющий символ). Затем он повторно заменяет ASCII 1 новыми строками, поэтому теперь каждая последовательность из нескольких строк помещается в одну строку, а старые разрывы строк заменяются на ASCII 2. Это grepped для cat, а затем ASCII 2 повторно заменяется на комбинация новой строки-пробел-пробел-пробел-пробел.

person Adam Rosenfield    schedule 21.11.2008

Что-то вроде этого?

awk 'function print_part() { if(cat) print part }  /^  / { part = part "\n" $0; next } /cat[0-9]$/ { print_part(); part = $0; cat = 1; next;  } { print_part(); cat=0} END { print_part() }' inputfile

Регулярное выражение /^ / идентифицирует строки продолжения.

Регулярное выражение /cat[0-9]$/ определяет начальные строки, которые вы хотите сохранить.

person activout.se    schedule 21.11.2008

Другой подход состоит в том, чтобы установить RS как нечто отличное от обычного \n. Например:

$ awk -v Pre=Wed 'BEGIN {RS = "\\n?\\s*" Pre} /cat.\n?/ {print Pre $0}' file.log
Wed Nov 12 blah blah blah blah cat1
Wed Nov 12 blah blah blah blah cat2
     more blah blah
     even more blah blah
Wed Nov 12 blah blah blah blah cat3
Wed Nov 12 blah blah blah blah cat4
person Community    schedule 18.04.2014