sed 与数值量词 - 如何?

sed 与数值量词 - 如何?

我正在尝试编辑多个文件的 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

我所做的一些改变是:

  1. 用作命令;的分隔符s///而不是默认的/。这让我们无法逃避/模式中的问题。几乎任何字符都可以用作分隔符,但应该选择一个不会出现在模式或替换文本中的字符。
  2. 仅使用标准的基本正则表达式语法。在您的模式中,(...)是扩展正则表达式语法,\{...\}是基本正则表达式语法。我决定使用基本语法来实现可移植性。这也意味着放弃-r在 GNU 中启用扩展语法的选项sed
  3. 分别使用 和 将图案锚定到线条的开头和^结尾$
  4. 不要尝试在替换位中插入换行符。

另一种更短的sed表达方式是

sed '/^>/s;/.\{0,10\}$;;'

这会将替换应用于以该>字符开头的所有行(/^>/充当后续s///命令的“地址”)。替换只是删除/及其后面到行尾的位如果该位的长度为 10 个字符或更少。

答案2

这是一种稍微不同的方法:

  1. 将输出保存到新文件:

    for file in *fa; do 
         sed -E 's|^\s*(>.{10,}.*)/.*|\1|' "$file" > "$file.fixed"; 
     done
    
  2. 就地编辑文件:

    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|'

相关内容