我有一个带有RX:的SAM文件,该字段包含12个碱基,中间用-
即RX:Z:CTGTGC-TCGTAA
隔开
我想从此字段中删除连字符,但是我不能简单地从整个文件中删除所有连字符,因为读取的名称包含它们,例如1713704_EP0004-T
大多数情况下都尝试使用tr,
,但这只是从文件中删除所有连字符。:
tr -d '"-' < sample.fq.unaln.umi.sam > sample.fq.unaln.umi.re.sam
输入是一个大于10,000,000行的大型SAM文件,如下所示:
1902336-103-016_C1D1_1E-T:34 99 chr1 131341 36 146M = 131376 182 GGACAGGGAGTGTTGACCCTGGGCGGCCCCCTGGAGCCACCTGCCCTGAAAGCCCAGGGCCCGCAACCCCACACACTTTGGGGCTGGTGGAACCTGGTAAAAGCTCACCTCCCACCATGGAGGAGGAGCCCTGGGCCCCTCAGGGG NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN MC:Z:147M MD:Z:83T62cD:i:4 cE:f:0 PG:Z:bwa RG:Z:A MI:Z:34 NM:i:1 cM:i:3 MQ:i:36 UQ:i:45 AS:i:141 XS:i:136 RX:Z:CTGTGC-TCGTAA
所需的输出(即最后一个字段)
1902336-103-016_C1D1_1E-T:34 99 chr1 131341 36 146M = 131376 182 GGACAGGGAGTGTTGACCCTGGGCGGCCCCCTGGAGCCACCTGCCCTGAAAGCCCAGGGCCCGCAACCCCACACACTTTGGGGCTGGTGGAACCTGGTAAAAGCTCACCTCCCACCATGGAGGAGGAGCCCTGGGCCCCTCAGGGG NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN MC:Z:147M MD:Z:83T62cD:i:4 cE:f:0 PG:Z:bwa RG:Z:A MI:Z:34 NM:i:1 cM:i:3 MQ:i:36 UQ:i:45 AS:i:141 XS:i:136 RX:Z:CTGTGCTCGTAA
如何解决此问题?
答案 0 :(得分:5)
awk
awk '{sub(/-/,"",$NF)}1' file
是您所需要的。
说明
sub(/-/,"",$NF)
用空字符串替换最后一个字段中的-
,使更改持久化。GNU sed
出于this相同的原因,
sed -Ei 's/^(.*)-/\1/' file
将起作用。它还有一个额外的优势,就是可以执行就地编辑。
说明
-E
选项启用扩展的正则表达式引擎。(.*)
是一种贪婪搜索,它将与任意字符(.
)匹配任意次数(*
)。对于贪婪的事实,它将匹配最后一个连字符。()
使sed
记住匹配的内容。\1
(1
,因为我们只有一对括号,请注意,您可以根据需要任意设置),而无需连字符,因此有效地将其从应该出现的最后一个字段中删除。 注意: GNU awk
支持-i inplace
,但是我不确定从哪个版本开始。
答案 1 :(得分:2)
我已经使用pysam解决了这个问题,该方法更快,更安全且所需的磁盘空间更少,因为不需要sam文件。这不是完美的,我仍在学习python并且已经使用pysam半天了。
import pysam
import sys
from re import sub
# Provide a bam file
if len(sys.argv) == 2:
assert sys.argv[1].endswith('.bam')
# Makes output filehandle
inbamfn = sys.argv[1]
outbamfn = sub('.bam$', '.fixRX.bam', inbamfn)
inbam = pysam.Samfile(inbamfn, 'rb')
outbam = pysam.Samfile(outbamfn, 'wb', template=inbam)
# Counters for reads processed and written
n = 0
w = 0
# .get_tag() retrieves RX tag from each read
for read in inbam.fetch(until_eof=True):
n += 1
umi = read.get_tag('RX')
assert umi is not None
umifix = umi[:6] + umi[7:]
read.set_tag('RX', umifix, value_type='Z')
if '-' in umifix:
print('Hyphen found in UMI:', umifix, read)
break
else:
w += 1
outbam.write(read)
inbam.close()
outbam.close()
print ('Processed', n, 'reads:\n',
w, 'UMIs written.\n',
str(int((w / n) * 100)) + '% of UMIs fixed')
答案 2 :(得分:1)
最好的解决方案是使用BAM而不是SAM文件,并使用适当的BAM解析器/编写器库,例如htslib。
缺少该功能,您可以通过在可选标签(第12列及以上)中搜索正则表达式^RX:Z:
来拼凑出一些东西。
在可能的情况下,使用sed很难处理列。相反,这是在awk中执行此操作的方法:
awk -F '[[:space:]]*' '{
for (i = 12; i <= NF; i++) {
if ($i ~ /^RX:Z:/) gsub("-", "", $i)
}
}
1' file.sam
这是与Perl“单线”大致等效的解决方案:
perl -ape '
for (@F[11..(scalar @F)]) {
s/-//g if /^RX:Z:/;
}
$_ = join("\t", @F);
' file.sam
要在原始文件中执行替换,您可以将选项-i.bak
传递给perl
(这将创建备份file.sam.bak
;如果您不想备份,请省略扩展名)。
答案 3 :(得分:0)
此模式在您要编辑的许多记录上,并且始终位于行尾吗?如果是这样-
sed -E 's/^(.*)(\s..:.:......)-(......\s*)$/\1\2\3/' < sample.fq.unaln.umi.sam > sample.fq.unaln.umi.re.sam