首页 > 解决方案 > 如何使用 sed 将匹配模式替换为行首?

问题描述

我有一个看起来像这样的文件:

254529  ANN=C|blabla,T|blabla,A|blabla
254540  ANN=T|blabla,G|blabla,C|blabla
254586  ANN=TTGG|blabla,A|blabla

我想用逗号替换文件中的逗号,后跟行首的数字。

blabla在我的文件中实际上是很长的文本,为了便于阅读,我在此处更改了这些文本。每个blabla都是不同的。

我尝试了以下方法,但它只替换了该行中的最后一个逗号。

sed -e 's/^\(.*\)\(\t.*\),/\1\2,\1\t/g' file

这是我得到的:

254529  ANN=C|blabla,T|blabla,254529    A|blabla
254540  ANN=T|blabla,G|blabla,254540    C|blabla
254586  ANN=TTGG|blabla,254586  A|blabla

虽然我想获得这个:

254529  ANN=C|blabla,254529    T|blabla,254529    A|blabla
254540  ANN=T|blabla,254540    G|blabla,254540    C|blabla
254586  ANN=TTGG|blabla,254586  A|blabla

这可以使用 sed 吗?

谢谢

标签: sed

解决方案


使用 sed

问题是g全局替换不会进行重叠替换。简单的解决方案是重复替换的次数与逗号相同。像这样:

$ sed ':a; s/^\(.*\)\(\t.*\),/\1\2\n\1\t/; ta; s/\n/,/g' file
254529  ANN=C|blabla,254529     T|blabla,254529 A|blabla
254540  ANN=T|blabla,254540     G|blabla,254540 C|blabla
254586  ANN=TTGG|blabla,254586  A|blabla

这个怎么运作:

  • :a

    这将创建一个标签a

  • s/^\(.*\)\(\t.*\),/\1\2\n\1\t/

    这将执行您的替换(稍作修改)。由于.*是“贪婪的”,因此它在该行的最后一个逗号处执行。

    由于.*是“贪婪的”,因此g修饰符是否被应用并不重要:只有最后一个逗号会被匹配,并且只会执行一次替换。

    与您的命令的一个区别是,在输出中,逗号替换为换行符。这样我们就不会再次尝试在同一个逗号上重复替换。

  • ta

    如果最后一次替换成功,则跳回标签 a。

  • s/\n/,/g

    将所有换行符转换回逗号。

使用 awk

$ awk -F'\t' '{gsub(/,/, ","$1"\t")} 1' file
254529  ANN=C|blabla,254529     T|blabla,254529 A|blabla
254540  ANN=T|blabla,254540     G|blabla,254540 C|blabla
254586  ANN=TTGG|blabla,254586  A|blabla

推荐阅读