所以我有一个带有基因标题的文本文件,并且同一物种下有不同的基因序列。因此,我提取了标头 (headers.txt) 并将其复制到另一个文件 ( uniqueheaders.txt
) 中。我删除了 中的所有重复项uniqueheaders.txt
。
我正在尝试循环读取一行,uniqueheaders.txt
然后循环读取headers.txt
以检查重复项。该if
语句检测重复项并增加计数器以将其附加到标头。这将对所有标头进行编号,headers.txt
以便我将它们插回我的 FASTA 文件中。我的代码在这里:
while IFS= read -r uniqueline
do
counter=0
while IFS= read headline
do
if [ "$uniqueline" == "$headline" ]
then
let "counter++"
#append counter to the headline variable to number it.
sed "$headline s/$/$counter/" -i headers
if
done < headers.txt
done < uniqueheaders.txt
问题是终端不断吐出错误
sed: -e expression #1, char 1: unknown command: 'M'
和
sed: -e expression #1, char 2: extra characters after command
这两个文件都包含唯一的标头名称:
Mus musculus
Homo sapiens
Rattus norvegicus
如何修改sed
命令来防止此错误?有更好的方法吗bash
?
输入示例(请注意,基因序列实际上并没有占用多少行的模式)**** 基因序列全部位于一个文件中
Mus musculus
MDFJSGHDFSBGKJBDFSGKJBDFS
NGBJDFSBGKJDFSHNGKJDFSGHG
Rattus norvegicus
SNOFBDSFNLSFSFSFSJFJSDFSD
Mus musculus
NJALDJASJDLAJSJAPOJPOASDJG
DSFHBDSFHSDFHDFSHJDFSJKSSF
期望的输出:
Mus musculus1
MDFJSGHDFSBGKJBDFSGKJBDFS
NGBJDFSBGKJDFSHNGKJDFSGHG
Rattus norvegicus
SNOFBDSFNLSFSFSFSJFJSDFSD
Mus musculus2
NJALDJASJDLAJSJAPOJPOASDJG
DSFHBDSFHSDFHDFSHJDFSJKSSF
答案1
awk
我想到了一个基于基础的解决方案。
由于您的头文件没有任何特定的标识,因此我们将采用“双文件双遍”方法,其中首先读取包含唯一标头的头文件,然后读取实际的序列文件两次,以便打印仅对那些出现多次的标头进行消歧编号:
awk 'NR==FNR{tot[$0]=0;next}
!final {if ($0 in tot) {tot[$0]++};next}
final && ($0 in tot) {if (tot[$0]>1) $0=$0 (++cnt[$0])}1' uniqueheaders.txt sequence.txt final="1" sequence.txt
- 如果
NR
全局行计数器等于FNR
每个文件的行计数器,我们就知道我们处于第一个要处理的文件(此处uniqueheaders.txt
)。然后,我们只需将标题“记录”在一个数组中tot
,该数组稍后将保存标题出现的总次数。 - 由于我们不知道有多少标题行和序列文件行,因此行计数器变量将无法帮助我们进一步识别我们所在的文件(至少如果我们不想依赖任何特定的
awk
实现) 。由于我们必须处理“序列文件”(您的示例输入)两次,以便禁止1
为那些仅出现一次的标头附加 a (请参阅此问答供讨论),我们将把它作为 的参数声明两次,但为第二遍awk
设置一个标志。final
- 在序列文件的第一遍(
final
尚未设置)中,我们只查看包含标题的那些行(即$0
整行位于数组的索引中tot
)并增加总出现次数计数器。 - 在序列文件的第二遍中(
final
现在设置为1
),我们通常打印所有行,但在作为标题行的那些行上(再次,通过$0
数组的索引来指示tot
),我们附加一个计数器(存储在数组中)cnt
),如果我们知道此标头有重复项 (tot[$0]>1
)。
笔记如果序列文件的标题行可以通过某种标准挑选出来(例如,所有基因序列都用空行分隔),那么我们就不需要外部文件,并且可以在一次调用uniqueheaders.txt
中完成这一切。awk