我有一个非常大的文件,具有以下基本格式,以及一些附加字段:
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
...解决这个问题的最佳方法是什么?
谢谢!
发布于 2017-06-20 14:24:59
以你的例子为例,最多有两个复合属性,然后使用简单的参数扩展和子字符串删除,你可以相当容易地完成你想要的,例如
#!/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,+发布于 2017-06-20 15:30:44
假设您的多个条目用分号;分隔,下面是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,-发布于 2017-06-22 01:35:30
最好的办法是把它分成三部分。
您有3个线型图案。一个有6列。另一个是12,最后一个是9。
6列=> 1行
12列=> 3行
9列=> 2行
您的6列不应被修改。这提醒了12和9,你可以在if、else if和else中将它们分开。像这样:
if( column == 6 ){...}
else if( column == 12 ){...}
else {...} 下面是一个Perl单行解决方案:
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,Gene3https://stackoverflow.com/questions/44644076
复制相似问题