繁体   English   中英

在sed中执行由反向引用定义的命令

[英]Execute command defined by backreference in sed

我正在创建一个完全基于sed的原始实验模板引擎(仅出于个人目的)。 我已经尝试了好几个小时了,现在要做的一件事是用它们包含的命令输出替换某些文本模式。

为了澄清,如果输入行看起来像这样

Lorem {{echo ipsum}}

我将看到sed输出看起来像这样:

Lorem ipsum

我最接近的是:

echo 'Lorem {{echo ipsum}}' | sed 's/{{\(.*\)}}/'"$(\\1)"'/g'

这不起作用。

然而,

echo 'Lorem {{echo ipsum}}' | sed 's/{{\(.*\)}}/'"$(echo \\1)"'/g'

给我

Lorem echo ipsum

我不太了解这里发生了什么。 为什么我可以将后向引用赋予echo命令,但不能在$()中评估整个后向引用? \\\\ 1什么时候得到评估? 我尝试使用纯sed甚至可以实现的目标吗?

请记住,对我来说,很清楚,使用其他工具可以轻松实现我要实现的目标。 但是,我对纯sed是否可以实现这一点非常感兴趣。

谢谢!

您的尝试不起作用的原因是$()在调用sed之前已被外壳扩展。 因此,它不能使用sed最终将要捕获的反向引用。

使用GNU sed(而不是POSIX sed)可以做这种事情。 主要技巧是GNU sed在s命令中带有一个e标志,使它用作为shell命令执行的模式空间的结果替换模式空间(整个空间)。 这意味着

echo 'echo foo' | sed 's/f/g/e'

打印goo

可以将其用于您的用例,如下所示:

echo 'Lorem {{echo ipsum}}' | sed ':a /\(.*\){{\(.*\)}}\(.*\)/ { h; s//\1\n\3/; x; s//\2/e; G; s/\(.*\)\n\(.*\)\n\(.*\)/\2\1\3/; ba }'

sed代码的工作方式如下:

:a                                    # jump label for looping, in case there are
                                      # several {{}} expressions in a line
/\(.*\){{\(.*\)}}\(.*\)/ {            # if there is a {{}} expression,
  h                                   # make a copy of the line
  s//\1\n\3/                          # isolate the surrounding parts
  x                                   # swap the original back in
  s//\2/e                             # isolate the command, execute, get output
  G                                   # get the outer parts we put into the hold
                                      # buffer
  s/\(.*\)\n\(.*\)\n\(.*\)/\2\1\3/    # rearrange the parts to put the command
                                      # output into the right place
  ba                                  # rinse, repeat until all {{}} are covered
}

这利用了正则表达式中sed的贪婪匹配来始终捕获一行中的最后一个{{}}表达式。 请注意,如果一行中有多个命令,而后一个命令具有多行输出,则会遇到困难。 处理这种情况将需要定义一个标记,即不允许嵌入在数据中的命令作为其输出的一部分,并且不允许包含模板。 我建议使用类似{{{}}} ,这将导致

sed ':a /\(.*\){{\(.*\)}}\(.*\)/ { h; s//{{{}}}\1{{{}}}\3/; x; s//\2/e; G; s/\(.*\)\n{{{}}}\(.*\){{{}}}\(.*\)/\2\1\3/; ba }'

其背后的原因是,如果嵌入式命令进一步打印{{}}项,则模板引擎无论如何都会遇到麻烦。 不能强制执行此约定,但是无论如何,传递给此模板引擎的任何代码最好都来自受信任的来源。

请注意,我不确定这整个事情是否是理智的想法1 您不打算在任何生产代码中使用它,对吗?

1但是,我很确定这是否是一个理智的想法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM