结合 xargs 与 sed 来修改或更改文件

结合 xargs 与 sed 来修改或更改文件

我在文件内部的行尾搜索一般模式 ***_23(但不是:at_23),然后尝试将所有这些结果更改为 \<23>,在同一个源文件中(插入函数是 sed -i),
我正在执行以下操作:

egrep '[b-s u v w x y z ]+_[0-9]+$' sst_piso_top_c0.spf_typ_C | xargs...

但我继续使用 sed 的所有尝试都失败了。

有人能解释一下 xargs 之后如何继续吗?我应该如何将列表传递给 sed 并告诉 sed 处理列表中的每个列表,并在同一个文件上进行更改?

答案1

也许我没有理解这个问题,但你只需要使用sed

$ sed -ri 's/[b-suvwxyz]+_([0-9]+)$/\\<\1>/g' sst_piso_top_c0.spf_typ_C

这里我们用来()捕获该值,然后\1在替换部分打印它。

答案2

无需组合egrepsed因为两个命令都会在文件中搜索匹配项并输出结果 ( egrep) 或对其执行操作 ( sed),所以sed单独使用即可。但为了理解为什么您的行不起作用,我将使用您的示例:

在多个文件上运行和在单个文件上运行的常规egrep输出形式为,而仅需要文件名。要抑制正常输出并仅打印包含匹配项的文件的名称,请使用该选项。filename:matching_linematching_linesedegrep-l

另外,您不希望字符列表中出现空格 ( [...]),否则它会过于贪婪并匹配多个单词。 一行可以正常工作:

$ egrep -l '[b-su-z]+_[0-9]+$' sst_piso_top_c0.spf_typ_C | xargs sed -ri 's/[b-su-z]+_([0-9])+$/\\<\1>/g'

如果复合命令不起作用,通常最好单独运行各个部分并检查其结果。此外,“没有这样的文件”之类的错误消息通常会为您指明正确的方向(最好将它们包含在您的报告中)。

最后,如上所述,将egrep和结合起来sed是没有意义的。合理的思路是

$ sed -ri 's/[b-su-z]+_([0-9])+$/\\<\1>/g' sst_piso_top_c0.spf_typ_C

更新:我的正则表达式中有一个拼写错误,我已更正。我还包含了对匹配中数字的反向引用,该引用最初由 zuazo 包含。从您现在写的评论中似乎更清楚,您不想像\<23>我最初理解的那样用静态表达式替换完整匹配,但您希望匹配的数字出现在尖括号中……

答案3

好的,为了满足您在问题下方的评论中澄清的要求,我会将事情分为两部分:

  1. at_排除最后一个数字之前的所有行
  2. 从剩余的行中,删除末尾的下划线,并将数字括在带有反斜杠的尖括号中。

第一部分的解决方案:

最简单的方法是编写一个正则表达式,与我们的然后告诉调用命令只输出那些需要的行不是匹配。使用 最容易实现这一点grep,因此让我们使用它:

egrep -v "at_[0-9]+" sst_piso_top_c0.spf_typ_C

-v或选项--invert-match告诉grep仅打印不匹配的行。

第 2 部分的解决方案:

sed使用s(替代)命令可以很容易地完成此操作:

sed -r 's/_([0-9]+)$/\\<\1\\>/g'

正则表达式匹配行末的下划线和数字。通过将数字部分括在括号中(...),我们可以将其粘贴到\1替换部分中。完整的替换部分由带反斜杠的尖括号组成,其中包含我们的数字反向引用\\<\1\\>。反斜杠需要用另一个反斜杠进行转义,\\因为它否则将被视为特殊转义字符。

综合起来:

egrep如果我们将1. 中的命令的输出通过管道传输到sed2. 中的命令,则sed命令将使用它作为输入流:

egrep -v "at_[0-9]+" sst_piso_top_c0.spf_typ_C | sed -r 's/_([0-9]+)$/\\<\1\\>/g' > sst_piso_top_c0.spf_typ_C.new

通常,sed结果将被发送到标准输出,因此上面这行将它们重定向到文件 ( > newfile)。请注意,此文件名必须与egrep正在读取的文件名不同,否则我们将覆盖正在读取的同一文件,最终得到一个空文件。

相关内容