Perl:带有shell命令的进程字符串(管道)

时间:2014-11-26 11:43:57

标签: perl pipe

假设有三个程序的管道:

start | middle | end

如果startend现在是一个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 dmiddle命令正在从start接收数据并对其进行处理,但输出将转到STDOUT而不是end。此外,尝试从middle读取似乎是从STDIN读取(因此命中ENTER的相关性)。

我知道这可以很容易地在一行perl(或sed)中完成;我的问题是如何在perl中管道,而不是如何替换字符串中的字符。

2 个答案:

答案 0 :(得分:3)

您可以使用IPC::Open2

此代码创建两个文件句柄:$to_sedprint可以向项目发送输入,$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不会做双向管道。