может ли awk заменить поля на основе отдельного файла спецификации? - PullRequest
2 голосов
/ 27 декабря 2011

У меня есть входной файл, подобный этому:

SomeSection.Foo
OtherSection.Foo
OtherSection.Goo

... и есть другой файл, описывающий, какой объект (ы) принадлежит каждому разделу:

[SomeSection]
Blah
Foo
[OtherSection]
Foo
Goo

Желаемыйвывод будет:

SomeSection.2   // that's because Foo appears 2nd in SomeSection
OtherSection.1  // that's because Foo appears 1st in OtherSection
OtherSection.2  // that's because Goo appears 2nd in OtherSection

(номера и имена разделов и объектов являются переменными)

Как бы вы сделали это в awk?

Заранее спасибоАдриан.

Ответы [ 2 ]

3 голосов
/ 28 декабря 2011

Одна возможность:

Содержимое script.awk (с комментариями):

## When 'FNR == NR', the first input file is in process.                                                                                                                                                                                     
## If line begins with '[', get the section string and reset the position                                                                                                                                                                           
## of its objects.                                                                                                                                                                                                                           
FNR == NR && $0 ~ /^\[/ {                                                                                                                                                                                                                    
        object = substr( $0, 2, length($0) - 2 )                                                                                                                                                                                             
        pos = 0
        next
}

## This section process the objects of each section. It saves them in
## an array. Variable 'pos' increments with each object processed.
FNR == NR {
        arr_obj[object, $0] = ++pos
        next
}

## This section process second file. It splits line in '.' to find second
## part in the array and prints all.
FNR < NR {
        ret = split( $0, obj, /\./ )
        if ( ret != 2 ) {
                next
        }
        printf "%s.%d\n", obj[1], arr_obj[ obj[1] SUBSEP obj[2] ]
}

Запустите скрипт (важен порядок входных файлов, object.txt имеет разделы с объектами и input.txt вызовы):

awk -f script.awk object.txt input.txt

Результат:

SomeSection.2
OtherSection.1
OtherSection.2

РЕДАКТИРОВАТЬ на вопрос в комментариях:

Я не эксперт, но постараюсь объяснить, как я это понимаю:

SUBSEP - это символ для разделения индексов в массиве, когда вы хотите использовать разные значения в качестве ключа. По умолчанию это \034, хотя вы можете изменить его как RS или FS.

В инструкции arr_obj[object, $0] = ++pos запятая объединяет все значения со значением SUBSEP, поэтому в этом случае будет получено:

arr_obj[SomeSection\034Blah] = 1

В конце скрипта я получаю доступ к индексу, используя explicity эту переменную arr_obj[ obj[1] SUBSEP obj[2], но с тем же значением, что и arr_obj[object, $0] в предыдущем разделе.

Вы также можете получить доступ к каждой части этого индекса, разделив ее с помощью переменной SUBSEP, например:

for (key in arr_obj) {                     ## Assign 'string\034string' to 'key' variable
    split( key, key_parts, SUBSEP )        ## Split 'key' with the content of SUBSEP variable.
    ...
}

с результатом:

key_parts[1] -> SomeSection
key_parts[2] -> Blah
2 голосов
/ 28 декабря 2011

эта строка awk должна выполнить работу:

 awk  'BEGIN{FS="[\\.\\]\\[]"}
        NR==FNR{ if(NF>1){ i=1; idx=$2; }else{ s[idx"."$1]=i; i++; } next; }
        { if($0 in s) print $1"."s[$0] } ' f2 input

см. Тест ниже:

kent$  head input f2
==> input <==
SomeSection.Foo
OtherSection.Foo
OtherSection.Goo

==> f2 <==
[SomeSection]
Blah
Foo
[OtherSection]
Foo
Goo

kent$  awk  'BEGIN{FS="[\\.\\]\\[]"}
        NR==FNR{ if(NF>1){ i=1; idx=$2; }else{ s[idx"."$1]=i; i++; } next; }
        { if($0 in s) print $1"."s[$0] } ' f2 input
SomeSection.2
OtherSection.1
OtherSection.2
...