Unix awk程序文件执行
由于我的最后一个问题越来越长,这里有一个当前代码级别的压缩版本 小结:我需要接收以管道分隔的输入文件,检查以确保所有适用的记录类型都存在,添加任何缺少的记录类型,并验证/更正每个记录类型中的子字段数 输入记录:Unix awk程序文件执行,unix,awk,Unix,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|
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
记录类型和子字段计数验证文件已知\u fld
条目:
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 )
}
在FNR==NR
部分,但除此之外,我的大脑简直是油炸了,我无法前进
我知道作为一个独立的,fix\u sub
区域可以工作。现在我只需要获取从known\u 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|||
原始问题:尝试修改后的脚本:
#!/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 )
}
这与您期望的输出不完全匹配。区别在于
GG
字段中的最后一个|
。我认为你所期望的产出没有达到。否则,在所有其他处理之后,最终字段的最终管道只需要删除。如果输入文件中的记录由~
分隔,字段由|
分隔,则您可能应该告诉awk
也这样做(即RS=“~”FS=“|”
)。然后,您可以对记录和字段进行更自然的操作。因为这只适用于输入(而不是字段文件),所以您可以在命令行上设置这些设置,如awk''FS='~'field_file RS='~'FS='|'input_file
,它将按您想要的方式工作。啊,如果您确实需要按行分割输入,那么这可能不太容易。。。但您可能仍然希望使用这种想法,在拆分成~
分隔字段后,在
上使用split()
。记录类型由~
分隔,但它仍然需要作为一条记录读取(供sqlldr以后使用)。真正的记录分隔符应该是RS='\n'
。~BB
条目中的E5TGE
在第一行哪里?标记字段(例如,~BB
是否计入字段计数(即,~BB | | | ~CC
是两个~BB
字段)?@EtanReisner:是的,记录类型标识符在字段计数中起作用。最终的结果是由sqlldr
使用,因此所有字段都必须进行计数。这很好!再次感谢您在解决这一棘手问题时提供的所有帮助。我可以处理最终的
。我主要不希望它出现在那里,因为se即使sqlldr
没有在控制文件中指定它,也不会将它作为最后一列来读取,但其他可能需要处理此问题的人可能会这样做。
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|||
#!/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 )
}
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||||