有没有办法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 的人:我知道它很丑陋,并且在生产中运行之前可能需要大量的打磨)