awk程序文件执行

由于我最后一个问题变得越来越长了,这里是当前代码级别的精简版本。

简介:我需要inputpipe道分隔的input文件,检查以确保所有适用的loggingtypes存在,添加缺less的任何内容,并validation/更正每个loggingtypes中的子字段数。

inputlogging:

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 

loggingtypes和子字段计数validation文件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 ) } 

我最初尝试执行子字段的validation和更正:

 #!/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) } 

上面的结果在达到第二个loggingtypes时出错。 所以现在我知道我需要从known_flds文件中捕获第二个值,以便将其传递给fix_sub函数。

我会join:

  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||| 

原始问题: 用于格式化pipe道分隔的分段文件的UNIX Shell Script解决scheme

试试这个修改的脚本:

 #!/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 subfld_cnt[$1] = $2 } 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); j++ } flds = flds (flds=="" ? "" : OFS) fld } print flds } function get_field_name(fnum, name) { name = $fnum sub(/\|.*$/, "", name) return( name ) } 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 = get_field_name(fnum) while(fld_rule[name] == "skp") { fnum++ name = $fnum sub(/\|.*$/, "", name) } return( fnum ) } function fix_sub(fnum, name, cnt, a, scnt, i, upd) { name = get_field_name(fnum) cnt = split($fnum, a, "|")-1 scnt = subfld_cnt[ name ] if(cnt != scnt) { for(i=1;i<=scnt;i++) upd = upd a[i] "|" return( upd ) } return( $fnum ) } 

关键区别:

  • subfld_cnt[$1] = $2已被添加到FNR==NR块中的req|opt部分(处理known_flds文件)
  • 增加了get_field_name()函数,它返回由它的fnum参数指定的字段的第一个子字段。
  • 从函数skip_flds()调用skip_flds()
  • 修改后的fix_sub()只接受fnum (所有其他变量都是本地函数),并根据需要修改子字段的数量。 现在对它的调用只需要在fix_sub(j)使用j参数。

fix_sub()更改的细分:

  • name = get_field_name(fnum)获取查找的字段名称
  • split $fnum ,并得到分裂的计数(离开你的-1调整)
  • scnt = subfld_cnt[ name ]从已添加到known_flds文件处理中的数组中获取所需的字段数。 这是你失踪的主要部分。
  • cnt != scnt修复子域时。
  • 留在你的upd设置代码中,但删除了upd = "" – 这已经完成了局部变量。
  • 个人喜好 – 直接返回值而不是else值。

我得到以下内容:

 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

|

这不完全符合您所需的输出。 最后的区别在于|GG领域。 我认为你想要的输出是缺少的。 否则,最终字段的最后一个管道只需要在所有其他处理之后被丢弃。