2009-09-08 3 views
3

У меня есть файлы данных из старой системы, которые я хотел бы обработать с помощью Awk. Каждый файл состоит из списка записей. Существует несколько разных типов записей, и каждый тип записи имеет другой набор полей фиксированной ширины (символ разделителя полей не существует). Первые два символа записи указывают тип, из этого вы затем знаете, какие поля должны следовать. Файл может выглядеть примерно так:Использование Awk для обработки файла, в котором у каждой записи есть разные поля фиксированной ширины.

AAField1Field2LongerField3 
BBField4Field5Field6VeryVeryLongField7Field8 
CCField99 

Использование Gawk я могу установить FIELDWIDTHS, но это относится ко всему файлу (если я не хватает какой-то способ настройки этого на запись-по-записи основе), или я могу настроить FS на «» и обрабатывать файл по одному символу за раз, но это немного громоздко.

Есть ли способ извлечь поля из такого файла с помощью Awk?

Edit: Да, я мог использовать Perl (или что-то еще). Я все еще хочу знать, есть ли разумный способ сделать это с Awk.

ответ

8

Надеемся, что это приведет вас в в правильном направлении. Предполагая, что ваши многострочные записи гарантированно завершатся строкой типа «CC», вы можете предварительно обработать ваш текстовый файл, используя простую логику if-then. Я предположил, что вам нужны поля1,5 и 7 в одной строке, а пример будет awk-скриптом.

BEGIN { 
     field1="" 
     field5="" 
     field7="" 
} 
{ 
    record_type = substr($0,1,2) 
    if (record_type == "AA") 
    { 
     field1=substr($0,3,6) 
    } 
    else if (record_type == "BB") 
    { 
     field5=substr($0,9,6) 
     field7=substr($0,21,18) 
    } 
    else if (record_type == "CC") 
    { 
     print field1"|"field5"|"field7 
    } 
} 

Создайте файл сценария awk, называемый program.awk, и введите этот код в него. Выполните сценарий, используя:

awk -f program.awk < my_multi_line_file.txt 
+2

Вы можете просто использовать сопоставление с ответом Джонатана Леффлера. Затем выполните извлечение подстроки. –

0

Лучше использовать некоторые полнофункциональные скриптовые языки, такие как perl или ruby.

3

Не могли бы вы использовать Perl, а затем выбрать шаблон распаковки, основанный на первых двух символах линии?

+0

Да, спасибо. Я не дотрагивался до Perl за десять лет, но если я не найду разумного способа добиться этого с помощью Awk, я могу следовать вашему предложению. –

0

Как насчет 2 сценариев? Например. 1-й скрипт вставляет разделители полей на основе первых символов, затем второй должен его обработать?

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

4

Вы, вероятно, нужно подавить (или по крайней мере игнорировать) awk «s встроенного кода разделения поля, а также использовать программу по линии:

awk '/^AA/ { manually process record AA out of $0 } 
    /^BB/ { manually process record BB out of $0 } 
    /^CC/ { manually process record CC out of $0 }' file ... 

ручной обработка будет немного неудобным - Полагаю, вам нужно будет использовать функцию substr для извлечения каждого поля по положению, поэтому то, что у меня есть как одна строка для каждого типа записи, будет больше похоже на одну строку на поле в каждом типе записи, а также на последующую печать.

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

+0

Я не думаю, что «' $ 0 ~ '» необходимо - часть '/^AA /' выполняет совпадение сама по себе. –

+0

Вы правы; то, что я написал, не ошибается, но и не минимально. –

5

Вы, возможно, можно использовать два прохода:

1step.awk

/^AA/{printf "2 6 6 12" } 
/^BB/{printf "2 6 6 6 18 6"} 
/^CC/{printf "2 8"   } 
{printf "\n%s\n", $0} 

2step.awk

NR%2 == 1 {FIELDWIDTHS=$0} 
NR%2 == 0 {print $2} 

А потом

awk -f 1step.awk sample | awk -f 2step.awk 

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

  • Нет связанных вопросов^_^