使用 sed 将结果保存在缓冲区中并将其用作另一个 sed 命令的模式

使用 sed 将结果保存在缓冲区中并将其用作另一个 sed 命令的模式

所以我开始了解 sed 中缓冲区的存在(模式缓冲区、保持缓冲区等),并思考是否有一种简单的方法来保存/保存或只是将 sed 命令的结果(例如:替换)重用为另一个命令/sed 调用?

假设我正在从管道的输出进行替换:

somecommand | sed 's/somepattern/somethingelse/g'

我想以某种方式重用上面替换的输出,我该怎么做?我知道我可以使用:

  1. 临时文件(例如:使用原始 mv + echo 等)
  2. 另一组管道、sed 调用和 xargs(例如:sed ... | xargs -I{} sed ...)

但以上两者都会阻止我仅有的使用 sed 的单次调用(这就是我想要在这里做的)。

如果我知道有这样的方法,我就会这样做:

somecommand | sed -i 's/somepattern/somethingelse/g;s/[reusing result from last substitution]/someotherthings/g' file

[] 之间的部分将重用替换结果作为模式或其他内容......

我确实尝试在 sed 文档中查找任何可能的解决方案,但没有太多示例(如果有的话)。

任何反馈/答案表示赞赏。

PS:上面示例的输出并不是真正的重点,但为了使事情更清楚,可以somecommand替换为:

echo "hello"

字面上地。

这是我尝试的另一件事,这将作为一个更容易理解的例子:

#!/bin/sh
echo -e "hello\nworld" | sed -n '
l #enable debugging
'/hello/' { # match the string from the echo pipe/command output
    s/hello/test/ #do a substitution
    p #print
    x # keep in
}'

我成功地完成了上半场;现在我需要知道如何使用驻留在其中的内容,x这样我就可以将它用于另一个替换(或任何其他 sed 调用/操作/命令)...

这是我尝试过的(但这次失败了):

#!/bin/sh
echo -e "hello\nworld" | sed -n '
l #enable debugging
'/hello/' { # match the string from the echo pipe/command output
    s/hello/test/ #do a substitution
    p #print
    x # keep in
    s/x/somethingelse/ # <---- what is failing
}'

这是行不通的。我猜有一种方法可以获取x这里的任何内容,但我不知道。

答案1

据我了解,您需要某种动态搜索模式,通过使用过去替换的输出作为另一个替换的模式。

我发现使用示例很有帮助。给定一个像这样的文件

green2
gold1
blue3
gold2
red4
more gold2 to find

现在你想用 a 替换每个12,并存储结果行,以便在再次出现时执行某些操作。在这个示例文件中,你可能想替换,gold2但你无法知道,因为在另一个文件中它可能不同。输出应该是

green2
gold2
blue3
replace
red4
more replace to replace

现实世界中可能存在类似的任务,您通常会sed这样处理这些任务:

sed -e 's/1/2/;tfound' -e 'G;s/\(..*\)\(.*\)\n\1$/replace\2/;P;d' -e ':found' -e h inputfile

其概念是将结果行存储在保持缓冲区中,并使用反向引用将每行与保持缓冲区进行匹配。详细地:

  • s/1/2/是显而易见的部分:你12
  • tfound:found表示在进行替换时进行分支标记。在这种情况下,该行存储在保留空间中,h并打印替换的行(如果您不想打印它,可以添加一个delete)
  • 现在是用于检查保持空间模式是否出现的行部分:G将保持空间附加到当前模式空间,因此模式空间包括
  • s/\(..*\)\(.*\)\n\1$/replace\2/在当前行中形成两组:第一个组\1在换行符之后重复,因此这是保留空间中的动态模式(注意,..*要求模式至少是一个字符,因此我们避免使用空的保留空间来匹配) ;第二个是该行的其余部分,不得删除,因此我们像\2替换中一样回收它
  • 如果进行了替换,我们可以打印该行,但如果没有替换,我们必须删除附加的内容。我们可以通过 来做到这一点s/\n.*//,但我们也可以使用该P命令仅打印第一行,然后delete 以避免默认输出。

这仅限于仅替换行中动态搜索模式的一次出现,但您可以轻松添加循环以使其适用于多次替换。

更新: OP澄清,第二阶段也应该应用于原始匹配行和所有后续行(直到新匹配),所以

hello
world
and test it

应该成为

替换世界并替换它

在这种情况下,您使用具有不同粘合逻辑的相同机制:

sed -ne '/hello/{s//test/;h;}' -e 'G;s/\(..*\)\(.*\)\n\1$/replace\2/;P'

选项-n抑制所有默认输出,因为所有所需的输出P现在都是通过命令完成的。对于匹配的字符串 ( hello),执行替换(空模式表示重复使用最后一个模式)并将其放入保持缓冲区,然后执行以下命令,因此下一次替换也在同一行中完成。

更新2: 在链接的示例中,hello根本不应修改这些行。您可以通过一些修改来做到这一点:

sed -ne '/hello/{h;s//test/;x;}' -e 'G;s/\(..*\)\(.*\)\n\1$/replace\2/;P'

相关内容