鉴于这种:
echo AAA | sed -r 's/A/echo B/ge'
我明白了:
Becho Becho B
我本以为我会得到“BBB”。这是 GNU sed 版本 4.2.1 的情况。发生了什么事,如何使用执行标志,并且可以在一行上进行多个替换(来自 shell,而不是来自 perl 等)?
答案1
这些标志以与您期望的相反的方式一起工作。这的文档/e
是, 作为记录:
该命令允许将 shell 命令的输入通过管道传送到模式空间。如果进行了替换,则执行在模式空间中找到的命令,并用其输出替换模式空间。尾随换行符被抑制;如果要执行的命令包含 null 字符,则结果未定义。这是一个 GNU sed 扩展。
写得有点曲折。这意味着,在完成s///
该行的命令后,如果发生更改,则(新)行将作为命令执行,其输出将用作该行的替换。
所以对于你给定的命令:
echo AAA | sed -r 's/A/echo B/ge'
它首先将每个替换A
为echo B
, 和然后将结果作为命令执行。它(粗略地说)与以下效果相同:
echo AAA | sed -r 's/A/echo B/g' | sh
GNUsed
不直接支持您想要的模式,尽管您可以根据需要使用更复杂的脚本来伪造它。或者,Perl/e
对其s
命令的修饰符确实具有您正在寻找的行为,但使用 Perl 表达式代替。
答案2
你是获得多次替换,但不会获得多次执行。一旦完成所有替换,就会执行该模式。
没有e
标志的结果
echo AAA | sed -r 's/A/echo B/g'
是
echo Becho Becho B
这就是如果您执行的命令行做包含e
标志,相当于
echo 'Becho Becho B'
答案3
要使用 GNU sed 的 's' 命令和 'e' 标志从 'AAA' 获取 'BBB',可以这样做:
echo AAA | sed -re 's/A/echo -n B;/ge'
“AAA”被替换为“echo -n B;echo -n B;” echo -n B;',最终执行时,会导致 3 个连续运行的 echo 命令,每个命令对应一个全局匹配。 '-n' 省略了 echo 输出中的换行符,使 'B' 最终在一行上(但 sed 在最终打印模式空间时自行附加一个换行符)。
答案4
一些东西:
(1) 您描述的确切用例可以通过以下方式处理
echo AAA | sed 's/A/B/g'
(2) 对于执行,如果这正是您想要的(为了比仅仅回显更高级的用法),您可以使用该e
标志作为最后一步:
echo AAA | sed -r 's/A/B/g;s/(.*)/echo \1/e'
(3) 如果您只想在第一个替代命令替换了某些内容时才执行该命令,请使用分支:
echo AAA | sed -r 's/A/B/g;te;b;:e;s/(.*)/echo \1/e'
sed
正如上面所写,这些仅适用于 GNU 。 BSD sed
(至少是我拥有的版本)不支持该-r
选项,并且需要字符串结尾来跟随分支名称。 (您可以通过添加带有参数的多个选项来解决最后一点-e
。)
请注意,对于给定的输入 (AAA),这三个单行代码在功能上都是相同的。但如果echo
命令更改为其他内容,或者选项-n
传递给sed
,您就会看到差异。