我有一个非常大的文件,其中包含以下基本格式,还有许多其他字段:
posA,id1,id2,posB,id3,name,(n additional fields)
1,ENST7,ENSP93,1,ENSG92,Gene1
2,ENST25;ENST76;ENST35,ENSP91;ENSP77;ENSP78,515;544;544,ENSG765,Gene2
3,ENST25;ENST76;ENST35,ENSP91;ENSP77;ENSP78,515;544;544,ENSG765,Gene2
4,ENST54;ENST93,ENSP83;ENSP36,1864;722,ENSG48,Gene3
5,ENST54;ENST93,ENSP83;ENSP36,1864;722,ENSG48,Gene3
6,ENST54;ENST93,ENSP83;ENSP36,1864;722,ENSG48,Gene3
第一行(posA = 1)每列有一个条目,不需要修改。对于某些列具有可变数量的多个条目的行,对于第三行(posA = 2),“id1”的第一个条目(ENST25)与“id2”(ENSP91)的第一个条目和第一个条目配对对于“posB”(515),依此类推,但具有单个条目的列(例如,“posA”,“id3”,“name”)适用于列2-4中的所有配对条目。除第2-4列之外的某些字段也很少包含多个条目。
我想将具有多个条目的列拆分为单独的行,同时保留其他列中的数据,如下所示:
posA,id1,id2,posB,id3,name,(n additional fields)
1,ENST7,ENSP93,1,ENSG92,Gene1
2,ENST25,ENSP91,515,ENSG765,Gene2
2,ENST76,ENSP77,544,ENSG765,Gene2
2,ENST35,ENSP78,544,ENSG765,Gene2
3,ENST25,ENSP91,515,ENSG765,Gene2
3,ENST76,ENSP77,544,ENSG765,Gene2
3,ENST35,ENSP78,544,ENSG765,Gene2
4,ENST54,ENSP83,1864,ENSG48,Gene3
4,ENST93,ENSP36,722,ENSG48,Gene3
...
解决此问题的最佳方法是什么?
谢谢!
答案 0 :(得分:0)
以你的例子为例,最多会有两个复合属性,然后使用简单的参数扩展和子串移除,你可以很容易地完成你想要的事情,例如。
#!/bin/bash
while IFS=, read -r p a1 a2 a3; do
[[ $a1 =~ ';' ]] && {
printf "%s,%s,%s,%s\n" "$p" "${a1%;*}" "${a2%;*}" "$a3"
printf "%s,%s,%s,%s\n" "$p" "${a1#*;}" "${a2#*;}" "$a3"
} || printf "%s,%s,%s,%s\n" "$p" "$a1" "$a2" "$a3"
done < "$1"
[[ $a1 =~ ';' ]]
检查';'
中$a1
的位置,如果找到,则选择$a1
中的第一个属性和$a2
${a1%;*}
和${a2%;*}
。然后,对于每个属性中的第二个属性,使用${a1#*;}
和${a2#*;}
。
如果';'
中不包含$a1
,则打印属性不变。 IFS=,
确保参数在','
上进行分词。
(注意:您应该将文件名有效的验证等添加到最终脚本中。如果您愿意,还可以使用echo
)
示例使用/输出
$ splitattrib.sh file
Pos,Attribute1,Attribute2,Attribute3
1,a,b,-
2,c,e,+
2,d,f,+
答案 1 :(得分:0)
假设您的多个条目以分号;
分隔,这是要执行的awk版本。
BEGIN {
FS="[,]"
}
{
if ($0 ~ /^[0-9].*/) {
end_split_field = 0
for (f=2;f<=NF;f++) {
if ($f ~ /.*;.*/) {
end_split_field=f
}
}
if (end_split_field == 0) {
print $0
} else {
for (f=2;f<=end_split_field;f++) {
n = split($f, a, ";") #split and return the number
for (i=1;i<=n;i++) {
b[f, i] = a[i]
}
}
for (i=1;i<=n;i++) {
printf $1","
for (j=2;j<=end_split_field;j++) {
printf b[j, i]","
}
for (k=end_split_field;k<NF;k++) {
printf $k","
}
printf $NF"\n"
}
}
} else {
print $0
}
}
将上面的内容保存为input.awk
,输入和输出示例
$ cat input
Pos,Attribute1,Attribute2,Attribute3
1,a,b,-
2,c;d,e;f,+
3,g;h;i,j;k;l,-
我们可以获得拆分输出
$ awk -f input.awk input
Pos,Attribute1,Attribute2,Attribute3
1,a,b,-
2,c,e,+
2,d,f,+
3,g,j,-
3,h,k,-
3,i,l,-
答案 2 :(得分:0)
最好是把它分成三部分。
你有3种线条图案。一个有6列。另一个有12个,最后一个是9.
6列=&gt; 1行
12列=&gt; 3行
9列=&gt; 2行
不应修改您的6列。所以提醒12和9.你可以在if
,else if
和else
中将它们分开。喜欢:
if( column == 6 ){...}
else if( column == 12 ){...}
else {...}
这是 Perl one-liner 解决方案:
perl -a -F",|;" -lne '$s=scalar @F;if($s==6){print join ",",@F}elsif($s==12){print join",",@F[0,1,4,7,-2,-1];print join",",@F[0,1,5,8,-2,-1];print join",",@F[0,1,6,9,-2,-1];}else{print join",",@F[0,1,3,5,-2,-1];print join",",@F[0,1,4,6,-2,-1]} ' file
并输入,输出为:
1,ENST7,ENSP93,1,ENSG92,Gene1
2,ENST25,ENSP91,515,ENSG765,Gene2
2,ENST25,ENSP77,544,ENSG765,Gene2
2,ENST25,ENSP78,544,ENSG765,Gene2
3,ENST25,ENSP91,515,ENSG765,Gene2
3,ENST25,ENSP77,544,ENSG765,Gene2
3,ENST25,ENSP78,544,ENSG765,Gene2
4,ENST54,ENSP83,1864,ENSG48,Gene3
4,ENST54,ENSP36,722,ENSG48,Gene3
5,ENST54,ENSP83,1864,ENSG48,Gene3
5,ENST54,ENSP36,722,ENSG48,Gene3
6,ENST54,ENSP83,1864,ENSG48,Gene3
6,ENST54,ENSP36,722,ENSG48,Gene3