我正在尝试按列名投影TSV文件。到目前为止,我从一个关于SO的问题中获取灵感,我正在使用这个脚本,t.awk
:
BEGIN {
OFS="\t"
split(cols,out,",")
}
NR==1 {
for (i=1; i<=NF; i++)
ix[$i] = i
}
NR>1 {
for (i=1;i<=length( out);i++)
printf "%s%s", $ix[out[i]], OFS
print ""
}
我可以调用:
awk -f t.awk -v cols=name1,name2,nameN input.tsv
除非cols
属性指定的其中一个名称不存在,否则它可以正常工作。
如何修改它以使其在这种情况下也有效?我想忽略作为参数传递的任何不存在的列名。
实施例(编辑): 考虑一下input.tsv:
a b c
1 2 3
2 3 4
5 6 7
我想要命令:
awk -f t.awk -v cols=a,c,batman input.tsv
生产:
a c
1 3
2 4
5 7
但是,到目前为止,它给出了:
awk: illegal field $(), name "batman"
答案 0 :(得分:1)
这是一个更简单的重写
$ awk -v cols='a,c,x' -v d=',' 'NR==1 {for(i=1;i<=NF;i++) if(d cols d ~ d $i d) ix[i]}
{for(i in ix) printf "%s", $i OFS;
print ""}' file
a c
1 3
2 4
5 7
列顺序可能不会被保留。
答案 1 :(得分:1)
你可以调整你的awk脚本:
BEGIN {
OFS="\t"
split(cols, out, ",")
for (i in out)
c[out[i]]
}
NR==1 {
for (i=1; i<=NF; i++)
if ($i in c)
hdr[i] = $i
}
{
k=0
for (i=1; i<=NF; i++)
if (i in hdr)
printf "%s%s", (k++?OFS:""), $i
print ""
}
然后将其运行为:
awk -f t.awk -v cols=a,c,batman input.tsv
或:
awk -f t.awk -v cols=c,batman,a input.tsv
两者都会产生这个输出:
a c
1 3
2 4
5 7
答案 2 :(得分:0)
这样做:
BEGIN {
FS=OFS="\t"
numIdxs = split(cols,idx2name,/,/)
}
NR==1 {
for (fldNr=1; fldNr<=NF; fldNr++) {
name2nr[$fldNr] = fldNr
}
next
}
{
for (idx=1; idx<=numIdxs; idx++) {
name = idx2name[idx]
if (name in name2nr) {
fldNr = name2nr[name]
fldVal = $(name2nr[fldNr])
printf "%s%s", (numPrinted++ ? OFS : ""), fldVal
}
}
}
numPrinted { print ""; numPrinted=0 }
相信我,当你遇到下雨天的情况时,如果你不得不回顾并稍后加强它,你会更开心。
请注意,与原始脚本一样,上面将按照您在命令行中指定的顺序输出字段,而不是输入文件中出现的顺序,因此您可以根据需要从命令行重新排列列。