由于我的最后一个问题太长,这里有一个包含当前代码级别的精简版本。
摘要:我需要接受一个以竖线分隔的输入文件,检查以确保所有适用的记录类型都存在,添加任何缺失的记录类型,并验证/更正每个记录类型中的子字段数量。
输入记录:
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
最佳答案
尝试这个修改后的脚本:
#!/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
block 中的req|opt
部分(处理known_flds
文件)- 添加了
get_field_name()
函数,该函数返回由其fnum
参数指定的字段的第一个子字段。 - 从函数
skip_flds()
调用get_field_name()
- 修改了
fix_sub()
以仅采用fnum
(所有其他变量都是函数的本地变量)并在必要时修复子字段管道的数量。现在,对它的调用仅需要一个j
参数,如fix_sub(j)
中所示。
fix_sub()
更改的详细信息:
name = get_field_name(fnum)
获取用于查找的字段名称分割
$fnum
,并获取分割的计数(保留 -1 调整)scnt = subfld_cnt[ name ]
从添加到known_flds
文件处理中的数组中获取所需的字段计数。这是你缺少的主要部分。- 当
cnt != scnt
时修复子fld。 - 保留
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
字段中最后的 |
。我认为您想要的输出缺少它。否则,在所有其他处理之后只需删除最终字段的最终管道。
关于unix - awk 程序文件执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30491496/