使用Perl:使用shell命令(管道)处理字符串

4
假设有三个程序的管道:

start | middle | end

如果 startend 现在是一个 Perl 脚本的一部分,如何通过 shell 命令将数据传递到 Perl 脚本中的管道中,以便经过 middle

我尝试了以下内容(抱歉没有使用严格模式,这只是一个简单的概念验证):

#!/usr/bin/perl -n

# Output of "start" stage
$start = "a b c d\n";

# This shell command is "middle"
open (PR, "| sed -E 's/a/-/g' |") or die 'Failed to start sed';

# Pipe data from "start" into "middle"
print PR $start;

# Read data from "middle" into "end"
$end = "";
while (<PR>) {
    $end .= $_;
}

close PR;

# Apply "end" and print output
$end =~ s/b/+/g;

print $end;

期望输出:

- + c d

实际输出:

没有输出,直到我按下回车键,然后我得到- b c dmiddle 命令从 start 接收数据并对其进行处理,但输出却发送到 STDOUT 而非 end。 此外,从 middle 读取数据似乎是从 STDIN 而不是 end(因此需要按下回车键)。

我知道这一切都可以在 perl(或 sed)的一行命令中轻松完成;我的问题是如何在 perl 中进行管道操作,而不是如何替换字符串中的字符。


й—®йўҳзҡ„еҸҰдёҖйғЁеҲҶжҳҜеҰӮдҪ•еңЁеҗ‘middleеҶҷе…Ҙstartж•°жҚ®еҗҺе…ій—ӯе…¶STDINпјҢеҗҢж—¶д»Қ然иғҪеӨҹд»Һmiddleзҡ„STDOUTиҜ»еҸ–пјҢзӣҙеҲ°е®ғиў«е…ій—ӯгҖӮ - Mark K Cowan
2个回答

3
你可以使用IPC::Open2来实现此功能。
这段代码创建了两个文件句柄:$to_sed,你可以使用print向其发送输入,和$from_sed,你可以使用readline(或<$from_sed>)从中读取程序的输出。
use IPC::Open2;

my $pid = open2(my ($from_sed, $to_sed), "sed -E 's/a/-/g'");

通常最简单的方法是使用shell,但也有一种替代调用方法,可以绕过shell,直接运行程序并填充其 argv 。该方法在链接的文档中有描述。


谢谢!我会记住这个,下次再用! - Mark K Cowan
现在就是那个时候了! - Mark K Cowan

2
你的代码在按回车键之前不执行任何操作,这是因为你正在使用perl -n。
-n 会让Perl假定程序周围有以下循环,使其类似于sed -n或awk,从而迭代文件名参数:
          LINE:
            while (<>) {
                ...             # your program goes here
            }

您的代码中读取文件的部分返回了空值。 如果您打开警告,您会发现Perl不支持双向管道。


哈哈,这总是这样。我猜你要解决的问题比你的例子复杂得多。双向IO很难。这可能会有所帮助。 - John C
我退回到三个单独的脚本和一个 shell 管道,尽管它可能稍微有些凌乱,但它运行良好!我主要是出于好奇在寻找一个 Perl 内部的管道解决方案。 - Mark K Cowan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接