2015-05-27 2 views
4

Как мой последний вопрос был длинным, вот сжатая версия с текущим уровнем кода.awk Выполнение программы

Реферат: Мне нужно взять входной файл с разделителями каналов, проверить наличие всех применимых типов записей, добавить отсутствующие и проверить/исправить количество подполей в каждом типе записи.

Входные записи:

AA|1234|ABCD|EDGFT|TR56BE|~BB||E5TGE|~CC|253641|84597|~DD|78HND|ACBE|||43|~EE|HISBL|78943|~FF|12345|SKIP|~GG|||TYBGFR 
AA|2345|CDEF|GFHIT|48UJKK|~CC||3FKTI 

типа записи и проверки файлов подсчета подполе known_flds записей:

AA~5~req 
BB~2~opt 
CC~3~opt 
DD~6~opt 
EE~4~opt 
FF~2~skp 
GG~4~opt 

Текущий сценарий, без коррекции подполе:

#!/usr/bin/awk -f 

BEGIN { FS=OFS="~" } 

FNR==NR { 
    dflts[$1] = create_empty_field($1,$2) 
    if($3 ~ /req|opt/) fld_order[++fld_cnt] = $1 
    fld_rule[$1] = $3 
    next 
} 

{ 
    flds = "" 
    j = 1 
    for(i=1; i<=fld_cnt; i++) { 
     j = skip_flds(j) 

     if($j !~ ("^" fld_order[i])) fld = dflts[fld_order[i]] 
     else { fld = $j; j++ } 
     flds = flds (flds=="" ? "" : OFS) fld 
    } 
    print flds 
} 

function create_empty_field(name, cnt,  fld, i) { 
    fld = name 
    for(i=1; i<=cnt; i++) { fld = fld "|" } 
    return(fld) 
} 

function skip_flds(fnum,  name) { 
    name = $fnum 
    sub(/\|.*$/, "", name) 
    while(fld_rule[name] == "skp") { 
     fnum++ 
     name = $fnum 
     sub(/\|.*$/, "", name) 
    } 
    return(fnum) 
} 

Моя первая попытка выполнение проверки и коррекции подполей:

#!/usr/bin/awk -f 

BEGIN { FS=OFS="~" } 

FNR==NR { 
    dflts[$1] = create_empty_field($1,$2) 
    if($3 ~ /req|opt/) fld_order[++fld_cnt] = $1 
    fld_rule[$1] = $3 
    next 
} 

{ 
    flds = "" 
    j = 1 
    for(i=1; i<=fld_cnt; i++) { 
     j = skip_flds(j) 
     if($j !~ ("^" fld_order[i])) fld = dflts[fld_order[i]] 
     else { fld = fix_sub($j,$2); j++ } 
     flds = flds (flds=="" ? "" : OFS) fld 
    } 
    print flds 
} 

function create_empty_field(name, cnt,  fld, i) { 
    fld = name 
    for(i=1; i<=cnt; i++) { fld = fld "|" } 
    return(fld) 
} 

function skip_flds(fnum,  name) { 
    name = $fnum 
    sub(/\|.*$/, "", name) 
    while(fld_rule[name] == "skp") { 
     fnum++ 
     name = $fnum 
     sub(/\|.*$/, "", name) 
    } 
    return(fnum) 
} 

function fix_sub(rec, num, upd, cnt) { 
    cnt=split(rec,a,"|")-1 
    upd="" 
    if(cnt != num) 
     {for(i=1;i<=$num;i++) 
     upd = upd a[i] "|" } 
    else { upd=$rec } 
    return(upd) 
} 

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

Я буду добавлять:

 sub_fld[$1] = $2 

В разделе FNR==NR, но кроме того, мой мозг просто жарят, и я не могу двигаться вперед.

Я знаю как самостоятельный, область fix_sub работает. Теперь мне просто нужно получить значение, считанное с known_flds.

Нужный выход:

AA|1234|ABCD|EDGFT|TR56BE|~BB||~CC|253641|84597|~DD|78HND|ACBE|||43|~EE|HISBL|78943||~GG|||TYBGFR 
AA|2345|CDEF|GFHIT|48UJKK|~BB||~CC||3FKTI|~DD||||||~EE||||~GG||| 

Оригинальный вопрос: UNIX Shell Script Solution for formatting a pipe-delimited, segmented file

+2

Если записи разделены символом '' 'и поля разделяются' '' во входном файле, то вы должны, вероятно, сказать 'awk' тоже сделать это (например,' RS = "~" FS = "|" ') , Затем вы получаете более естественную операцию по записям и полям. Так как это верно только для ввода (а не файла поля), вы можете установить их в командной строке, как этот 'awk '