假设有三个程序的管道:
start | middle | end
如果start
和end
现在是一个perl脚本的一部分,我如何通过perl脚本中的shell命令管道数据,以便通过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
实际输出:
none,直到我点击ENTER,然后我得到- b c d
。 middle
命令正在从start
接收数据并对其进行处理,但输出将转到STDOUT而不是end
。此外,尝试从middle
读取似乎是从STDIN读取(因此命中ENTER的相关性)。
我知道这可以很容易地在一行perl(或sed)中完成;我的问题是如何在perl中管道,而不是如何替换字符串中的字符。
答案 0 :(得分:3)
您可以使用IPC::Open2
。
此代码创建两个文件句柄:$to_sed
,print
可以向项目发送输入,$from_sed
可以readline
(或{{ 1}})来自读取程序的输出。
<$from_sed>
最常见的是涉及shell最简单,但有一个替代调用允许您绕过shell而是运行程序并直接填充其use IPC::Open2;
my $pid = open2(my ($from_sed, $to_sed), "sed -E 's/a/-/g'");
。它在链接文档中进行了描述。
答案 1 :(得分:2)
你的代码在输入之前什么都不做的原因是因为你使用的是perl -n。
-n使Perl假定程序周围有以下循环,这使得它迭代文件名参数 有点像sed -n或awk:
LINE:
while (<>) {
... # your program goes here
}
代码中您再次读取文件的部分不会返回任何内容。 如果你打开警告,你会发现perl不会做双向管道。