我在文件内部的行尾搜索一般模式 ***_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
无需组合egrep
,sed
因为两个命令都会在文件中搜索匹配项并输出结果 ( egrep
) 或对其执行操作 ( sed
),所以sed
单独使用即可。但为了理解为什么您的行不起作用,我将使用您的示例:
在多个文件上运行和在单个文件上运行的常规egrep
输出形式为,而仅需要文件名。要抑制正常输出并仅打印包含匹配项的文件的名称,请使用该选项。filename:matching_line
matching_line
sed
egrep
-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
好的,为了满足您在问题下方的评论中澄清的要求,我会将事情分为两部分:
at_
排除最后一个数字之前的所有行- 从剩余的行中,删除末尾的下划线,并将数字括在带有反斜杠的尖括号中。
第一部分的解决方案:
最简单的方法是编写一个正则表达式,与我们的不然后告诉调用命令只输出那些需要的行不是匹配。使用 最容易实现这一点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. 中的命令的输出通过管道传输到sed
2. 中的命令,则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
正在读取的文件名不同,否则我们将覆盖正在读取的同一文件,最终得到一个空文件。