sed 命令用于替换遵循模式的行中的单词

sed 命令用于替换遵循模式的行中的单词

我正在处理如下所示的文件,其中包含超过 50,000 行基因 ID 及其序列:

gene_A:3342234 CTCTTTCTTTTACGCCT
gene_A:1244-5205 CTCTTTCTTTTACGCCT
gene_A:1838438 CTCTTTCTTTTACGCCT
gene_B:1848584 CTCTTTCTTTTACGCCT
gene_B:1029-4920 CTCTTTCTTTTACGCCT
gene_C:3849029 CTCTTTCTTTTACGCCT

它们都有基因 ID,后跟冒号,然后是 7-9 位数字的参考号和(有些包括破折号)。

我想用它们的实际名称替换基因 ID,例如geneAgeneB,同时保留它们后面的信息。期望的输出:

geneA CTCTTTCTTTTACGCCT
geneA CTCTTTCTTTTACGCCT
geneA CTCTTTCTTTTACGCCT
geneB CTCTTTCTTTTACGCCT
geneB CTCTTTCTTTTACGCCT
geneB CTCTTTCTTTTACGCCT

这是我第一次使用 sed,所以我真的不太确定从哪里开始。我知道如何替换所有包含gene_A 的行,'s/gene_A.*/geneA/'但我不确定如何保留基因ID 后面的信息。

答案1

我怀疑你的例子很糟糕,你实际上必须以某种方式将基因 ID 映射到基因名称,而不是以编程方式转换它们,例如使用如下文件:

$ cat ids2names
gene_A when
gene_B chapmen
gene_C billies

如果是这样,那么您可以使用任何 awk 执行以下操作:

$ awk -F'[: ]' 'NR==FNR{map[$1]=$2; next} {print map[$1], $3}' ids2names file
when CTCTTTCTTTTACGCCT
when CTCTTTCTTTTACGCCT
when CTCTTTCTTTTACGCCT
chapmen CTCTTTCTTTTACGCCT
chapmen CTCTTTCTTTTACGCCT
billies CTCTTTCTTTTACGCCT

否则,如果基因名称实际上只是一个基因 ID,_如您的示例中所示,则删除了...

使用任何 sed:

$ sed 's/_\([^:]*\)[^ ]*/\1/' file
geneA CTCTTTCTTTTACGCCT
geneA CTCTTTCTTTTACGCCT
geneA CTCTTTCTTTTACGCCT
geneB CTCTTTCTTTTACGCCT
geneB CTCTTTCTTTTACGCCT
geneC CTCTTTCTTTTACGCCT

或任何 awk:

$ awk -F'[_: ]' '{print $1 $2, $4}' file
geneA CTCTTTCTTTTACGCCT
geneA CTCTTTCTTTTACGCCT
geneA CTCTTTCTTTTACGCCT
geneB CTCTTTCTTTTACGCCT
geneB CTCTTTCTTTTACGCCT
geneC CTCTTTCTTTTACGCCT

如果输入中的空格并不总是单个空格,则更改为-F'[: ]'awk脚本中的-F'[:[:blank:]]+'或(如果存在,则保留)以及sed 脚本中的或。-F'[: \t]+'_[^ ][^[:blank:]][^ \t]

当查门比利时

答案2

使用(以前称为 Perl_6)

~$ raku -pe 's/^  \w+  <( \: <[0..9-]>+  //;'   file 

#OR

~$ raku -pe 's/^ (\w+)    \: <[0..9-]>+ /$0/;'  file

以上是用 Raku(Perl 编程语言家族的成员)编写的答案。这两个答案使用 Raku 的-pe类似 sed 的自动打印逐行标志(可以设想其他答案使用 Raku 的-ne类似 awk 的非自动打印逐行标志)。

简而言之,^检测字符串的开头(行),后跟\w+一个或多个数字或下划线,后跟\:冒号,再后跟由<[0..9-]>+阿拉伯数字和-连字符组成的自定义字符类。 (要包含 Unicode 数字,请<+ :N + [-]>+改用)。

输入示例:

gene_A:3342234 CTCTTTCTTTTACGCCT
gene_A:1244-5205 CTCTTTCTTTTACGCCT
gene_A:1838438 CTCTTTCTTTTACGCCT
gene_B:1848584 CTCTTTCTTTTACGCCT
gene_B:1029-4920 CTCTTTCTTTTACGCCT
gene_C:3849029 CTCTTTCTTTTACGCCT

示例输出(两个代码示例):

gene_A CTCTTTCTTTTACGCCT
gene_A CTCTTTCTTTTACGCCT
gene_A CTCTTTCTTTTACGCCT
gene_B CTCTTTCTTTTACGCCT
gene_B CTCTTTCTTTTACGCCT
gene_C CTCTTTCTTTTACGCCT

每个答案的解释:

  1. Raku 的<(捕获标记用于删除冒号之前的匹配项(注意捕获标记单独工作,但可以同时使用<(和/或)。)>然后剩余的捕获在替换的一半中被“无替换”,即删除。

  2. Raku 的()数字捕获括号用于捕获基因名称,本质上是在之后放弃匹配。然后,现在的捕获$0被放置在替换半场中,即删除比赛的剩余部分。


注意:如果确实需要“捕获然后修改”(即删除基因名称中的下划线),那么 Raku 可以让您在替换的一半中运行代码。下面trans将所有下划线转换为空字符串(即什么都没有),返回删除下划线的基因名称:

~$ raku -pe 's/^ (\w+) \: <[0..9-]>+ /{$0.trans("_" => "")}/;'  file

#OR (more simply)

~$ raku -pe 's/^ (\w+) \: <[0..9-]>+ /$0.trans("_" => "")/;'  file

https://docs.raku.org/language/regexes
https://raku.org

答案3

sed -E 's/(gene_[A-Z]):[0-9-]+/\1/' input.txt

该命令使用-E选项来启用扩展正则表达式并捕获组中的基因 ID (gene_[A-Z]),后跟冒号以及一系列数字和破折号:[0-9-]+。替换\1是指原始输入文件中的基因 ID,该文件包含基因 ID 列表,后跟其序列,在此示例中名为 input.txt。

答案4

我会分两步完成此操作sed

假设gene.txt

gene_A:3342234 CTCTTTCTTTTACGCCT
gene_A:1244-5205 CTCTTTCTTTTACGCCT
gene_A:1838438 CTCTTTCTTTTACGCCT
gene_B:1848584 CTCTTTCTTTTACGCCT
gene_B:1029-4920 CTCTTTCTTTTACGCCT
gene_C:3849029 CTCTTTCTTTTACGCCT
  1. 删除中间字段(由 a:到 a分隔):

    > sed 's/:.* / /' gene.txt
    gene_A CTCTTTCTTTTACGCCT
    gene_A CTCTTTCTTTTACGCCT
    gene_A CTCTTTCTTTTACGCCT
    gene_B CTCTTTCTTTTACGCCT
    gene_B CTCTTTCTTTTACGCCT
    gene_C CTCTTTCTTTTACGCCT
    

    此命令从冒号到空格匹配,然后用空格替换所有内容。

  2. 删除下划线(添加到第一个命令上):

    > sed 's/:.* / /;s/_//' gene.txt
    geneA CTCTTTCTTTTACGCCT
    geneA CTCTTTCTTTTACGCCT
    geneA CTCTTTCTTTTACGCCT
    geneB CTCTTTCTTTTACGCCT
    geneB CTCTTTCTTTTACGCCT
    geneC CTCTTTCTTTTACGCCT
    

    此命令使用分号来分隔两次独立的替换尝试,但如果发生第一次替换,则第二次替换仍将在第一次替换的结果上发生。此解决方案的“措辞”仅删除第一个下划线(g任一替换末尾都没有)。

相关内容