我正在尝试提取同一文本文件中不同行上出现的序列 ID 和簇编号。
输入看起来像
>Cluster 72
0 319aa, >O311_01007... *
>Cluster 73
0 318aa, >1494_00753... *
1 318aa, >1621_00002... at 99.69%
2 318aa, >1622_00575... at 99.37%
3 318aa, >1633_00422... at 99.37%
4 318aa, >O136_00307... at 99.69%
>Cluster 74
0 318aa, >O139_01028... *
1 318aa, >O142_00961... at 99.69%
>Cluster 75
0 318aa, >O300_00856... *
所需的输出是一列中的序列 ID 和第二列中的相应簇编号。
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75
有人能帮忙吗?
答案1
使用 awk:
awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
- 我们用空格或句点来分割字段
-F '[. ]*'
- 有两个字段的行(行
>Cluster
),将第二个字段保存为 ID 并移动到下一行 - 与其他行一起,打印第三个字段和保存的 ID
答案2
你可以使用awk
以下方法:
awk '/>Cluster/{
c=$2;
next
}{
print substr($3,2,length($3)-4), c
}' file
第一个块语句用于捕获集群 ID。第二个块语句(默认)用于提取所需数据并打印。
答案3
下面是使用 Ruby 的另一种方法:
ruby -ne 'case $_; when /^>Cluster (\d+)/;id = $1;when /, (>\w{4}_\w{5})\.\.\./;puts "#{$1} #{id}";end' input_file
或分布在多行:
ruby -ne 'case $_
when /^>Cluster (\d+)/
id = $1
when /, (>\w{4}_\w{5})\.\.\./
puts "#{$1} #{id}"
end' input_file
我猜如果你了解 Ruby 和正则表达式,那么它比这个版本更易读awk
。作为奖励,这个代码可能比简单地分割行更健壮一些,因为它会查找周围的文本。
答案4
Perl:
$ perl -ne 'if(/^>.*?(\d+)/){$n=$1;}else{ s/.*(>[^.]+).*/$1 $n/; print}' file
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75
解释
perl -ne
:逐行读取输入文件(-n
)并将给出的脚本应用-e
到每一行。if(/^>.*?(\d+)/){$n=$1;}
:如果此行以 开头>
,则找出行末最长的数字,并将其保存为$n
。else{ s/.*(>[^.]+).*/$1 $n/; print
:如果该行不是以 开头,则用( )后面>
最长的非字符段替换所有内容,即序列名称(因为我们有.
>
>[^.]+
$1
被捕获正则表达式匹配)和 的当前值$n
。
或者,采用更类似 awk 的方法:
$ perl -lane 'if($#F==1){$n=$F[1]}else{$F[2]=~s/\.+$//; print "$F[2] $n"}' file
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75
这只是一种稍微麻烦一点的方法,但可以实现与各种awk
方法相同的基本思想。我将其包括进来是为了完整性和 Perl 粉丝。如果您需要解释,只需使用 awk 解决方案 :)。