关于bash:如何为每个标题添加一个数字,对目录中的每个文件都是唯一的?

How to add a number to every header, unique to each file in a directory?

我有一个包含数百个多 FASTA 文件的目录。

在每个文件头中遵循相同的命名逻辑,如:

>Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]

其中:

> 是每个标题的开头

Bubo_bubo 是物种名称(与 FASTA 文件的名称相同,此处为:Bubo_bubo.fasta)

c5_g1_i1 是序列的规范,所有其他字符都是关于特定序列的附加信息

我想要做的是在特定文件中的每个标题中添加相同的数字,在物种名称和有关该文件的其他信息之间,以获得类似:

>Bubo_bubo_001_c5_g1_i1 len=168 path=[174:0-148 24:148-168]

我希望每个文件的数字都不同。你能帮我解决一下吗?


这是使用 Perl 的一种方法

输入文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ ls -1 Bubo_bubo*fasta
Bubo_bubo.fasta
Bubo_bubo2.fasta
Bubo_bubo3.fasta
Bubo_bubo4.fasta

$ cat Bubo_bubo.fasta
>Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
a b c

$ cat Bubo_bubo2.fasta
>Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
d e f

$ cat Bubo_bubo3.fasta
>Bubo_bubo3_chihoig len=134 path=[174:0-148 24:148-168]
g h i

$ cat Bubo_bubo4.fasta
>Bubo_bubo4_wrwklk_gjf len-133 path=[174:0-148 24:148-168]
p q r

解决方案:

Perl -i 就地替换所有文件。

1
$ perl -i.bak -pe ' if($.==1) { $y=sprintf("%03d",++$x); s/^>((.+?)_(.+?))_/>\\1_${y}_/ } close(ARGV) if eof ' Bubo_bubo*fasta

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cat Bubo_bubo.fasta
>Bubo_bubo_001_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
a b c

$ cat Bubo_bubo2.fasta
>Bubo_bubo_002_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
d e f

$ cat Bubo_bubo3.fasta
>Bubo_bubo3_003_chihoig len=134 path=[174:0-148 24:148-168]
g h i

$ cat Bubo_bubo4.fasta
>Bubo_bubo4_004_wrwklk_gjf len-133 path=[174:0-148 24:148-168]
p q r


这有点冗长,但我认为它会完成这项工作:

1
2
awk 'BEGIN{FS="_"}filename!=FILENAME{++uniquenumber;filename=FILENAME}/^>/{printf"%s_%s_%03d_%s_%s_%s\
", $1,$2,uniquenumber,$3,$4,$5 > FILENAME"_updated";next}{print $0 > FILENAME"_updated"}'
*

那会:

  • 在处理 (BEGIN{}) 之前,将字段分隔符设置为下划线。
  • 如果变量 filename 不等于我们正在处理的当前文件 filename 然后将 uniquenumber 变量增加 1 并将 filename 变量设置为我们正在处理的当前文件名 filename
  • 如果该行以 > (/^>/) 开头
  • 然后打印出使用前导 0 将唯一数字添加到三个字符的行: (printf"%s_%s_%03d_%s_%s_%s\
    ", $1,$2,uniquenumber,$3,$4,$5
    )
  • 重定向输出相同的文件名,但带有 _updated 后缀(您现在将拥有一个包含更改的新文件。并继续到文件中的下一行 (> FILENAME"_updated";next)
  • 如果您还在这里,那么我们就在常规线路上。只需将其打印到相同的 _updated 文件:{print $0 > FILENAME"_updated"}
  • 对此目录中的所有文件执行此操作 *
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    ~/fasta$ ls
    file1  file2  file3
    ~/fasta$ cat *
    >Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    blah
    blah
    >Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    blah
    >Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    foo
    bar
    foo
    >Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    foo
    >Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]

    _bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    whatevfs
    >Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    asd
    >Bubo_bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    ~/fasta$ awk 'BEGIN{FS="_"}filename!=FILENAME{++uniquenumber;filename=FILENAME}/^>/{printf"%s_%s_%03d_%s_%s_%s\
    ", $1,$2,uniquenumber,$3,$4,$5 > FILENAME"_updated";next}{print $0 > FILENAME"_updated"}'
    file*
    ~/fasta$ cat *updated
    >Bubo_bubo_001_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    blah
    blah
    >Bubo_bubo_001_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    blah
    >Bubo_bubo_002_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    foo
    bar
    foo
    >Bubo_bubo_002_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    foo
    >Bubo_bubo_002_c5_g1_i1 len=168 path=[174:0-148 24:148-168]

    _bubo_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    whatevfs
    >Bubo_bubo_003_c5_g1_i1 len=168 path=[174:0-148 24:148-168]
    asd
    >Bubo_bubo_003_c5_g1_i1 len=168 path=[174:0-148 24:148-168]