我有一个带有重复标题的输入文件(如下所示):
A1BG A1BG A1CF A1CF A2ML1
aa bb cc dd ee
1 2 3 4 5
我想在一个文件中打印具有相同标题的所有列。例如,对于上面的文件,应该有三个输出文件; 1个A1BG,2列; A1CF第2列,2列; A2ML1的第3列,1列。我有没有办法用awk或grep使用单行?
我试过跟随单行:
awk -v f="A1BG" '!o{for(x=1;x<=NF;x++)if($x==f){o=1;next}}o{print $x}' trial.txt
但是这只在一列中搜索模式(在这种情况下为1)。我想查看所有标题名称并打印其标题中包含A1BG的所有相应列。
答案 0 :(得分:1)
我无法帮助你使用1-liner,但这里有一个10-liner for GNU awk:
<强> script.awk 强>
NR == 1 { PROCINFO["sorted_in"] = "@ind_num_asc"
for( i=1; i<=NF; i++ ) { f2c[$i] = (i==1)? i : f2c[$i] " " i } }
{ for( n in f2c ) {
split( f2c[n], fls, " ")
tmp = ""
for( f in fls ) tmp = (f ==1) ? $fls[f] : tmp "\t" $fls[f]
print tmp > n
}
}
像这样使用:awk -f script.awk your_file
在第一个操作中:它确定第一个记录(NR == 1
)中列的文件名。
在第二个操作中:对于每个记录:对于每个输出文件:其列(在第一个记录中定义)被收集到tmp
并写入输出文件。
使用PROCINFO需要GNU awk,请参阅Ed Mortons对备选方案的评论。
示例运行和输出:
> awk -f mpapccfaf.awk mpapccfaf.csv
> cat A1BG
A1BG A1BG
aa bb
1 2
答案 1 :(得分:1)
awk解决方案应该非常快 - 输出文件以制表符分隔并命名为cols.A1BG cols.A1CF等
awk '
# fill cols columns map to header and tab map to track tab state per header
NR==1 {
for(i=1; i<=NF; ++i) {
cols[i]=$i
tab[$i]=0
}
}
{
# reset tab state for every header
for(h in tab) tab[h]=0
# write tab-delimited column to its cols.header file
for(i=1; i<=NF; ++i) {
hdr=cols[i]
of="cols." hdr
if(tab[hdr]) {
printf("\t") >of
} else
tab[hdr]=1
printf("%s", $i) >of
}
# newline for every header file
for(h in tab) {
of="cols." h
printf("\n") >of
}
}
'
这是我的两个awk解决方案的输出:
$ ./scr.sh <in.txt; head cols.*
==> cols.A1BG <==
A1BG A1BG
aa bb
1 2
==> cols.A1CF <==
A1CF A1CF
cc dd
3 4
==> cols.A2ML1 <==
A2ML1
ee
5
答案 2 :(得分:1)
这个awk解决方案采用与Lars相同的方法,但使用gawk 4.0 2D阵列
ComboBox
答案 3 :(得分:0)
在这里,根据要求提出单行:
awk 'NR==1{for(i=1;i<=NF;i++)a[$i][i]}{PROCINFO["sorted_in"]="@ind_num_asc";for(n in a){c=0;for(f in a[n])printf"%s%s",(c++?OFS:""),$f>n;print"">n}}' file
以上使用GNU awk 4. *表示真正的多维数组和sorted_in。
对于其他阅读此内容的人而言,他们更倾向于明确OP需要的简洁性,这里它是一个更自然的多行脚本:
$ cat tst.awk
NR==1 {
for (i=1; i<=NF; i++) {
names2fldNrs[$i][i]
}
}
{
PROCINFO["sorted_in"] = "@ind_num_asc"
for (name in names2fldNrs) {
c = 0
for (fldNr in names2fldNrs[name]) {
printf "%s%s", (c++ ? OFS : ""), $fldNr > name
}
print "" > name
}
}
$ awk -f tst.awk file
$ cat A1BG
A1BG A1BG
aa bb
1 2
$ cat A1CF
A1CF A1CF
cc dd
3 4
$ cat A2ML1
A2ML1
ee
答案 4 :(得分:0)
由于您在其中一条评论中写道,您有20000列,我们可以考虑采用两步方法来简化调试,找出哪些步骤中断。
<强> step1.awk 强>
NR == 1 { PROCINFO["sorted_in"] = "@ind_num_asc"
for( i=1; i<=NF; i++ ) { f2c[$i] = (f2c[$i]=="")? "$" i : (f2c[$i] " $" i) } }
NR== 2 { for( fn in f2c) printf("%s:%s\n", fn,f2c[fn])
exit
}
Step1应该为我们提供一个文件列表以及他们的列:
> awk -f step1.awk yourfile
Mpap_1:$1, $2, $3, $5, $13, $19, $25
Mpap_2:$4, $6, $8, $12, $14, $16, $20, $22, $26, $28
Mpap_3:$7, $9, $10, $11, $15, $17, $18, $21, $23, $24, $27, $29, $30
在我的测试数据中,Mpap_1是第1,2,3,5,13,19,25栏中的标题。让我们希望这第一步适用于您的大量列。 (坦率地说:我不知道awk是否可以处理20000美元。)
第2步:让我们创建一个着名的一个衬垫:
> awk -f step1.awk yourfile | awk -F : 'BEGIN {print "{"}; {print " print " $2, "> \"" $1 "\"" }; END { print "}" }' | awk -v "OFS=\t" -f - yourfile
第一部分是我们的第1步,第二部分是动态构建第二个awk脚本,使用这样的行:print $1, $2, $3, $5, $13, $19, $25 > "Mpap_1"
。第二个awk脚本通过管道传输到第三部分,该部分从stdin(-f -
)读取脚本并将脚本应用于输入文件。
如果某些东西不起作用:观察step2的每个部分的输出,你可以执行左边的部分直到(但不包括)每个|
符号,看看发生了什么,例如:
awk -f step1.awk yourfile
awk -f step1.awk yourfile | awk -F : 'BEGIN {print "{"}; {print " print " $2, "> \"" $1 "\"" }; END { print "}" }'
答案 5 :(得分:0)
以下为我工作:
step1.awk的代码:
NR == 1 {PROCINFO [“sorted_in”] =“@ ind_num_asc” for(i = 1; i&lt; = NF; i ++){f2c [$ i] =(f2c [$ i] ==“”)? “$”我:(f2c [$ i]“\”\ t \“$”i)}} NR == 2 {for(fn in f2c)printf(“%s:%s \ n”,fn,f2c [fn]) 出口 }
然后运行一个使用上面awk脚本的衬垫:
awk -f step1.awk file.txt | awk -F:'BEGIN {print“{”}; {print“print”$ 2,“&gt; \”“$ 1”.txt“”\“”}; END {print“}”}'| awk -f - file.txt
这会输出制表符分隔的.txt文件,其中所有列都在一个文件中具有相同的标题。 (每种类型标题的单独文件)
感谢Lars Fischer和其他人。
干杯