2012-05-30 4 views
5

мне нужно обработать большой файл данных, который содержит многострочные записи, пример ввод:использование AWK для идентификации записи несколько строк и фильтрации

1 Name  Dan 
1 Title  Professor 
1 Address aaa street 
1 City  xxx city 
1 State  yyy 
1 Phone  123-456-7890 
2 Name  Luke 
2 Title  Professor 
2 Address bbb street 
2 City  xxx city 
3 Name  Tom 
3 Title  Associate Professor 
3 Like  Golf 
4 Name 
4 Title  Trainer 
4 Likes  Running 

Обратите внимание, что первое целое поле является уникальным и действительно идентифицирую в целом запись. Таким образом, в приведенном выше вводе у меня действительно есть 4 записи, хотя я не знаю, сколько строк атрибутов может иметь каждая запись. Мне нужно: - определить действительную запись (должно иметь поле «Имя» и «Название») - выводить доступные атрибуты для каждой действительной записи, например «Имя», «Заголовок», «Адрес» - это необходимые поля.

Пример вывода:

1 Name  Dan 
1 Title  Professor 
1 Address aaa street 
2 Name  Luke 
2 Title  Professor 
2 Address bbb street 
3 Name  Tom 
3 Title  Associate Professor 

Таким образом, в выходном файле, запись 4 удаляется, поскольку она doen't есть поле "Name". Запись 3 не имеет поля «Адрес», но все еще печатается на выходе, так как это действительная запись с именами «Имя» и «Заголовок».

Могу ли я сделать это с помощью awk? Но как я могу идентифицировать целую запись, используя первое поле «id» в каждой строке?

Большое спасибо эксперту по сценарию unix shell, который помогает мне! :)

ответ

6

Это похоже на работу. Есть много способов сделать это, даже в awk.

Я расставил его для удобства чтения.

Обратите внимание, что запись 3 не отображается, поскольку отсутствует поле «Адрес», которое вы определили по мере необходимости.

#!/usr/bin/awk -f 

BEGIN { 
     # Set your required fields here... 
     required["Name"]=1; 
     required["Title"]=1; 
     required["Address"]=1; 

     # Count the required fields 
     for (i in required) enough++; 
} 

# Note that this will run on the first record, but only to initialize variables 
$1 != last1 { 
     if (hits >= enough) { 
       printf("%s",output); 
     } 
     last1=$1; output=""; hits=0; 
} 

# This appends the current line to a buffer, followed by the record separator (RS) 
{ output=output $0 RS } 

# Count the required fields; used to determine whether to print the buffer 
required[$2] { hits++ } 

END { 
     # Print the final buffer, since we only print on the next record 
     if (hits >= enough) { 
       printf("%s",output); 
     } 
} 
+0

благодарит за вашу помощь! Мне потребовалось немного времени, чтобы переварить ваше решение, а потом я многому научился! :) Очень благодарен! Спасло меня так много времени, как и многому научилось от этого :) – trillions

+0

никаких проблем! рад, что это было полезно. – ghoti

+0

почти +1 - в основном очень приятно. Вы можете отказаться от предложения NR == 1. Вопрос, как представляется, слегка неоднозначен в отношении того, требуется ли «Адрес». Тем не менее, я прочитал его как * не * (требуется запись 3 должна быть выведена). Когда я запускаю ваш скрипт с пропущенной строкой «Адрес», я получаю все четыре записи вместо 1-3, несмотря на то, что «Имя» пусто для записи 4. Причина этого в том, что ваш селектор ' required [$ 2] 'создает элемент массива, соответствующий каждому имени поля, просто ссылаясь на *, и вы не проверяете, что он равен' 1' *. –

3

Я плохо разбираюсь в awk, но я бы решил это на Perl. Вот решение Perl: для каждой записи он запоминает важные строки и видно ли название и название. В конце записи запись печатается, если выполняются все условия.

#!/usr/bin/perl 
use warnings; 
use strict; 

my ($last, $has_name, $has_title, @record); 
while (<DATA>) { 
    my ($id, $key, $value) = split; 
    if ($id != $last and @record) { 
     print @record if $has_name and $has_title; 
     undef @record; 
     undef $has_name; 
     undef $has_title; 
    } 
    $has_name = 1 if $key eq 'Name'; 
    $has_title = 1 if $key eq 'Title'; 
    push @record, $_ if grep $key eq $_, qw/Name Address Title/; 
    $last = $id; 
} 


__DATA__ 
1 Name  Dan 
1 Title  Professor 
1 Address aaa street 
1 City  xxx city 
1 State  yyy 
1 Phone  123-456-7890 
2 Name  Luke 
2 Title  Professor 
2 Address bbb street 
2 City  xxx city 
3 Name  Tom 
3 Title  Associate Professor 
3 Like  Golf 
4 Name 
4 Title  Trainer 
4 Likes  Running 
+0

благодарит за ваше решение perl! Я попробую это позже. Теперь я пойду с awk, так как мне все еще нужно немного модифицировать скрипт для моей следующей необходимости, которая не размещена здесь. – trillions

Смежные вопросы