2013-02-08 3 views
1

Система обертывает строки в файле журнала, если они превышают X символов. Я пытаюсь извлечь различные данные из журнала, но сначала мне нужно объединить все разделенные строки, поэтому gawk может анализировать поля как одну запись.Объединение разделенных линий с awk/gawk

Например:

2012/11/01 field1 field2 field3 field4 fi 
eld5 field6 field7 
2012/11/03 field1 field2 field3 
2012/12/31 field1 field2 field3 field4 fi 
eld5 field6 field7 field8 field9 field10 
field11 field12 field13 
2013/01/10 field1 field2 field3 
2013/01/11 field1 field2 field3 field4 

Я хочу вернуть

2012/11/01 field1 field2 field3 field4 field5 field6 field7 
2012/11/03 field1 field2 field3 
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11 field12 field13 
2013/01/10 field1 field2 field3 
2013/01/11 field1 field2 field3 field4 

Фактическая максимальная длина строки в моем случае это 130. Я неохотно проверить, что длина и использовать getline присоединиться следующая строка, если есть запись длиной в 130 символов.

После того, как я очистил файл журнала, я также собираюсь хотеть извлечь все соответствующие события, где «соответствующие» могут быть связаны критерии, как:

  • «Foo» где-либо в какой-либо поле в записи
  • field2 ~/бара | DTN/
  • если field1 ~/хуг | а/& & field98 == "0001"

Мне интересно, нужно ли мне запускать две последовательные программы gawk или если я могу объединить все это в одно.

Я в поглазеть новичок и прихожу из не-Unix

+1

Вы можете сделать все это за одну команду awk. Вы бросили нас (ну, по крайней мере, я), попросив сценарий объединить строки, я даже не заметил последней части о том, что вы действительно хотите сделать с данными, которые делают вещи «я могу объединить строки» излишним. –

ответ

2
$ awk '{printf "%s%s",($1 ~ "/" ? rs : ""),$0; rs=RS} END{print ""}' file 
2012/11/01 field1 field2 field3 field4 field5 field6 field7 
2012/11/03 field1 field2 field3 
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11 field12 field13 
2013/01/10 field1 field2 field3 
2013/01/11 field1 field2 field3 field4 

Теперь, когда я заметил, что ты на самом деле не хотите просто напечатать рекомбинированные записи, вот альтернативный способ сделать это, это более восприимчивыми, чтобы проверить на перекомпилированной записи («s» в этом сценарии:

$ awk 'NR>1 && $1~"/"{print s; s=""} {s=s $0} END{print s}' file 

Теперь с этой структурой, а не только печать s можно выполнить проверку на с, например, (обратите внимание на «Foo» в 3-й записи):

$ cat file 
2012/11/01 field1 field2 field3 field4 fi 
eld5 field6 field7 
2012/11/03 field1 field2 field3 
2012/12/31 field1 field2 foo field4 fi 
eld5 field6 field7 field8 field9 field10 
field11 field12 field13 
2013/01/10 field1 field2 field3 
2013/01/11 field1 field2 field3 field4 

$ awk ' 
function tst(rec,  flds,nf,i) { 
    nf=split(rec,flds) 
    if (rec ~ "foo") { 
     print rec 
     for (i=1;i<=nf;i++) 
     print "\t",i,flds[i] 
    } 
} 
NR>1 && $1~"/" { tst(s); s="" } 
{ s=s $0 } 
END { tst(s) } 
' file 
2012/12/31 field1 field2 foo field4 field5 field6 field7 field8 field9 field10 field11 field12 field13 
     1 2012/12/31 
     2 field1 
     3 field2 
     4 foo 
     5 field4 
     6 field5 
     7 field6 
     8 field7 
     9 field8 
     10 field9 
     11 field10 
     12 field11 
     13 field12 
     14 field13 
+0

Brilliant. Я знал, когда читаю все команды gawk и примеры, что, вероятно, будет этот холодно эффективный однострочный, который сделал именно то, что мне нужно (чтобы объединить строки) без всяких тестов и условий. Вы пригвоздили это. И да, ваш второй пример выглядит так, как мне нужно будет обрабатывать записи. У меня есть одна проблема: некоторые записи содержат 700 символов с 125 + полями. Интересно, может ли 'split' е, что многие. –

+0

не будет проблемой. –

2
gawk '{ gsub("\n", ""); printf $0 RT } 
    END { print }' RS='\n[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]' input 

Это может быть несколько упрощен:

gawk --re-interval '{ gsub("\n", ""); printf $0 RT } 
    END { print }' RS='\n[0-9]{4}/[0-9]{2}/[0-9]{2}' input 
1

Вот немного больше подходит Perl, который также обрабатывает дополнительную фильтрация (как вы помечены этот Perl а):

[email protected]:~# cat combine_and_filter.pl 
#!/usr/bin/perl -n 

if (m!^2\d{3}/\d{2}/\d{2} !){ 
    print $prevline if $prevline =~ m/field13/; 
    $prevline = $_; 
}else{ 
    chomp($prevline); 
    $prevline .= $_ 
} 


[email protected]:~# perl combine_and_filter < /tmp/in.txt 
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11 field12 field13 
+0

Я признаюсь, что я отметил его perl только потому, что, похоже, в Perl-юниверсе много пользователей awk/gawk, и я не был уверен, что получаю много ответов, если бы он был просто помечен awk/gawk. Как-то мой исходный пост был усечен, где я объяснил, что ...;) –

1

это может работать для вас:

awk --re-interval '/^[0-9]{4}\//&&s{print s;s=""}{s=s""sprintf($0)}END{print s}' file 

тест с вашим примером:

kent$ echo "2012/11/01 field1 field2 field3 field4 fi 
eld5 field6 field7 
2012/11/03 field1 field2 field3 
2012/12/31 field1 field2 field3 field4 fi 
eld5 field6 field7 field8 field9 field10 
field11 field12 field13 
2013/01/10 field1 field2 field3 
2013/01/11 field1 field2 field3 field4"|awk --re-interval '/^[0-9]{4}\//&&s{print s;s=""}{s=s""sprintf($0)}END{print s}' 
2012/11/01 field1 field2 field3 field4 field5 field6 field7 
2012/11/03 field1 field2 field3 
2012/12/31 field1 field2 field3 field4 field5 field6 field7 field8 field9 field10 field11 field12 field13 
2013/01/10 field1 field2 field3 
2013/01/11 field1 field2 field3 field4 
+1

do not do 'sprintf ($ 0)', поскольку он ничего не делает, если $ 0 не содержит символ форматирования printf, но затем он дает вам ошибку «out out» если $ 0 содержит символ форматирования. Всегда используйте поле формата и поле данных при использовании [s] printf для входных данных. Выполнение конкатенации строк с помощью пустой строки ('s = s" "...') также ничего не делает –

+0

@EdMorton thx для комментария. Хороший комментарий! +1 – Kent

0

Вот очень короткий сценарий для acccomplish это.

sed '/^[[:digit:]]/ { :r N; /\n\([^[:digit:]]\)/ s:: \1:g; tr; } ' FILE 

Вы счастливы с этим в этой форме?

2

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

sed -r ':a;$!N;\#\n[0-9]{4}/[0-9]{2}/[0-9]{2}#!{s/\n//;ta};P;D' file 
Смежные вопросы