如何以跨平台方式管道传输两个 Perl CORE::system 命令?

Posted

技术标签:

【中文标题】如何以跨平台方式管道传输两个 Perl CORE::system 命令?【英文标题】:How can I pipe two Perl CORE::system commands in a cross-platform way? 【发布时间】:2010-05-27 21:57:34 【问题描述】:

我正在编写一个 System::Wrapper 模块来抽象出 CORE::systemqx 运算符。我有一个serial 方法,它尝试将command1 的输出连接到command2 的输入。我在使用命名管道方面取得了一些进展,但 POSIX::mkfifo 不是跨平台的。

这是我到目前为止的部分内容(底部的run 方法基本上调用system):

package main;

my $obj1 = System::Wrapper->new(
    interpreter => 'perl',
    arguments   => [-pe => q''],
    input       => ['input.txt'],
    description => 'Concatenate input.txt to STDOUT',
);

my $obj2 = System::Wrapper->new(
    interpreter => 'perl',
    arguments   => [-pe => q'$_ = reverse $_'],
    description => 'Reverse lines of input input',
    output      =>  '>' => 'output' ,
);

$obj1->serial( $obj2 );


package System::Wrapper;

#...

sub serial 
    my ($self, @commands) = @_;

    eval 
        require POSIX; POSIX->import();
        require threads;
    ;

    my $tmp_dir = File::Spec->tmpdir();

    my $last = $self;

    my @threads;

    push @commands, $self;

    for my $command (@commands) 

        croak sprintf
        "%s::serial: type of args to serial must be '%s', not '%s'",
        ref $self, ref $self, ref $command || $command
        unless ref $command eq ref $self;

        my $named_pipe = File::Spec->catfile( $tmp_dir, int \$command );

        POSIX::mkfifo( $named_pipe, 0777 )
          or croak sprintf
          "%s::serial: couldn't create named pipe %s: %s",
          ref $self, $named_pipe, $!;

        $last->output(  '>' => $named_pipe  );
        $command->input( $named_pipe );

        push @threads, threads->new( sub $last->run  );
        $last = $command;
    

    $_->join for @threads;


#...

我的具体问题:

    有没有跨平台的POSIX::mkfifo 的替代品? Win32 命名管道不起作用,因为您不能将它们作为常规文件打开,套接字也不能,出于同样的原因。

    2。上面的不太奏效;两个线程正确生成,但没有任何东西流过管道。我想这可能与管道死锁或输出缓冲有关。让我失望的是,当我在实际的 shell 中运行这两个命令时,一切都按预期工作。

第 2 点已解决; -p fifo 文件测试没有测试正确的文件。

【问题讨论】:

【参考方案1】:

出于兴趣,为什么需要 FIFO?难道你不能只设置一个常规管道(例如使用pipe?)当你可以使用更强大的支持fork时,为什么还要使用线程?

事实上,您可以改为使用 CPAN 模块来为您完成大部分工作。 IPC::Run 例如:

use IPC::Run qw(run);
run ['perl', '-pe', ''], '<', 'input.txt', '|', ['perl', '-pe', '$_ = reverse $_'], '>', 'output';

...在 Linux 或 Windows 上应该可以正常工作。

【讨论】:

我不能使用常规管道,也不能使用 IPC::Run,因为我不能保证程序可以将有意义的输出打印到 STDOUT 或从 STDIN 读取。某些程序可能需要将输入或输出文件设置为参数,否则会死机。关于forkthreads,我的印象是fork 实际上在Windows 下不太健壮。但是我没有真正的理由在 fork 上使用线程。

以上是关于如何以跨平台方式管道传输两个 Perl CORE::system 命令?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Perl 将输入通过管道传输到 Java 应用程序?

如何 grep/perl/awk 重叠正则表达式

如何在 ASP.NET Core 的 .json 配置文件中以跨平台方式存储文件路径?

perl:一个父母,许多孩子 - 父母中有一个管道阅读器?

ASP.NET Core管道深度剖析:采用管道处理HTTP请求

ASP.NET Core管道深度剖析[共4篇]