我正在尝试编辑多个文件的 fasta 标头,以便删除正斜杠及其后面的所有内容(只要“后面的所有内容”等于或小于 10 个字符)。标题行用“>”标记。
for i in ./*.fa;do sed -r 's/(>.*)\/.\{,10\}\n/\1\n/' "$i"; done
我也尝试过
for i in ./*.fa;do sed -r 's/(>.*)\/.{,10}\n/\1\n/' "$i"; done
但情况似乎并没有好转。我的直觉是 {,10} 量词破坏了一切。但我不确定。非常感谢您的帮助!
例如,如果文件中有以下内容:
>header1_some_extra_data_here/1-1000
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA
我希望输出如下:
>header1_some_extra_data_here
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA
答案1
您的sed
替换将无法按预期工作,因为您永远无法匹配输入数据中的换行符。这是因为sed
逐行读取文件,即使用换行符作为分隔符,并且表达式将单独应用于行,而不使用分隔换行符。
相反,稍微改变你的代码:
for fasta in ./*.fa; do
sed 's;^\(>.*\)/.\{0,10\}$;\1;' "$fasta"
done
我所做的一些改变是:
- 用作命令
;
的分隔符s///
而不是默认的/
。这让我们无法逃避/
模式中的问题。几乎任何字符都可以用作分隔符,但应该选择一个不会出现在模式或替换文本中的字符。 - 仅使用标准的基本正则表达式语法。在您的模式中,
(...)
是扩展正则表达式语法,\{...\}
是基本正则表达式语法。我决定使用基本语法来实现可移植性。这也意味着放弃-r
在 GNU 中启用扩展语法的选项sed
。 - 分别使用 和 将图案锚定到线条的开头和
^
结尾$
。 - 不要尝试在替换位中插入换行符。
另一种更短的sed
表达方式是
sed '/^>/s;/.\{0,10\}$;;'
这会将替换应用于以该>
字符开头的所有行(/^>/
充当后续s///
命令的“地址”)。替换只是删除/
及其后面到行尾的位如果该位的长度为 10 个字符或更少。
答案2
这是一种稍微不同的方法:
将输出保存到新文件:
for file in *fa; do sed -E 's|^\s*(>.{10,}.*)/.*|\1|' "$file" > "$file.fixed"; done
就地编辑文件:
sed -i -E 's|^\s*(>.{10,}.*)/.*|\1|' *.fa
该-E
选项启用扩展正则表达式。这让我们可以用于()
捕获和{}
重复,而无需转义它们。为了清楚起见,我还将分隔符更改为|
,并添加了^\s*
(请注意,您的 可能不支持这一点sed
;如果不支持,您可以^ *
改为使用),因为有时您可以在 之前有空格>
它),因为有时在 fasta 文件
然后,技巧是匹配 a>
后跟 10 个或更多字符,直到 a /
,用括号捕获这些字符,使它们成为\1
并仅用匹配的部分替换整行。
请注意,这将找到最长的 >10 个字符,直到最后一个/
。因此,如果同一行有多个/
,则将保留除最后一个之外的所有内容。例如:
$ echo ">header1_some_extra_data_here/1-1000/foo/bar/baz" |
sed -E 's|^\s*(>.{10,}.*)/.*|\1|'
>header1_some_extra_data_here/1-1000/foo/bar
为了避免这种情况,并删除第一个字符之后的所有内容/
(只要您已经匹配了 10 个字符),请使用:
sed -E 's|^\s*(>.{10}[^/]*)/.*|\1|'