在替换之前通过外部程序管道 sed 捕获组?

在替换之前通过外部程序管道 sed 捕获组?

有没有办法sed将捕获组通过管道传输到另一个程序,使\1正则表达式的 RHS 等于该程序的输出?

例如,运行

sed 's/lorem ipsum \(foobar\)/\1/g' file.txt

是否会通过另一个程序(例如tr 'o' 'a')将“foobar”管道化为\1“faabar”,以sed将“lorem ipsum foobar”替换为“lorem ipsum faabar”?

这只是一个简单的例子。我意识到我可以将“foobar”转换为“faabar”而不使用tr.

答案1

您可以使用 GNU sed - 使用e(execute) 修饰符:

e
此命令允许将 shell 命令的输入通过管道传送到模式空间。如果进行了替换,则执行在模式空间中找到的命令,并用其输出替换模式空间。尾随换行符被抑制;如果要执行的命令包含 NUL 字符,则结果未定义。这是一个 GNU sed 扩展。

来源

但它的用处有限,因为它执行并替换整个模式空间,而不是指定的捕获组。所以你需要跳过一些相当丑陋的圈子。

前任。

$ echo 'lorem ipsum foobar' | sed '
    s/\(lorem ipsum \)\(foobar\)/printf "%s%s" "\1" "$(echo "\2" | tr o a)"/e
  '
lorem ipsum faabar

答案2

据我所知:没有。

可以使用以下命令将模式空间写入文件

sed  '/example/w file'

但不是捕获组。您可以使用以下命令执行外部程序

sed 'e ls'

你可以用以下命令读取文件

sed 'r file'

但我没有看到一种可维护的方法来完成你所要求的事情。坦率地说,你正处于这里有用的边缘sed

awk这里可能更灵活一些,但这是perl你最好的选择,正如@ikkachu 在他的评论中已经建议的那样。

作为一个简短的想法,它是多么微不足道perl

while (<>){
    if (/(.*)(pattern)(.*)/){
        $pre=$1;
        $pat=$2;
        $post=$3;
        $repl=`filter_pgm $pat`;
        print $pre . $repl . $post;
    }
    else {
        print;
    }
}

(对于那些更精通 Perl 的人:我知道它很丑陋,并且在生产中运行之前可能需要大量的打磨)

相关内容