![sed 命令用于替换遵循模式的行中的单词](https://linux22.com/image/228862/sed%20%E5%91%BD%E4%BB%A4%E7%94%A8%E4%BA%8E%E6%9B%BF%E6%8D%A2%E9%81%B5%E5%BE%AA%E6%A8%A1%E5%BC%8F%E7%9A%84%E8%A1%8C%E4%B8%AD%E7%9A%84%E5%8D%95%E8%AF%8D.png)
我正在处理如下所示的文件,其中包含超过 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,例如geneA
和geneB
,同时保留它们后面的信息。期望的输出:
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
每个答案的解释:
Raku 的
<(
捕获标记用于删除冒号之前的匹配项(注意捕获标记单独工作,但可以同时使用<(
和/或)。)>
然后剩余的捕获在替换的一半中被“无替换”,即删除。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
答案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
删除中间字段(由 a
:
到 a分隔):
> sed 's/:.* / /' gene.txt gene_A CTCTTTCTTTTACGCCT gene_A CTCTTTCTTTTACGCCT gene_A CTCTTTCTTTTACGCCT gene_B CTCTTTCTTTTACGCCT gene_B CTCTTTCTTTTACGCCT gene_C CTCTTTCTTTTACGCCT
此命令从冒号到空格匹配,然后用空格替换所有内容。
删除下划线(添加到第一个命令上):
> sed 's/:.* / /;s/_//' gene.txt geneA CTCTTTCTTTTACGCCT geneA CTCTTTCTTTTACGCCT geneA CTCTTTCTTTTACGCCT geneB CTCTTTCTTTTACGCCT geneB CTCTTTCTTTTACGCCT geneC CTCTTTCTTTTACGCCT
此命令使用分号来分隔两次独立的替换尝试,但如果发生第一次替换,则第二次替换仍将在第一次替换的结果上发生。此解决方案的“措辞”仅删除第一个下划线(
g
任一替换末尾都没有)。