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

发布于 2024-09-03 02:56:31 字数 2046 浏览 6 评论 0原文

我正在编写一个 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;
}

#...

我的具体问题:

  1. 是否有 POSIX 的替代方案::mkfifo 是跨平台的吗? Win32 命名管道不起作用,因为您无法将它们作为常规文件打开,套接字也不起作用,原因相同。

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

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

I'm writing a System::Wrapper module to abstract away from CORE::system and the qx operator. I have a serial method that attempts to connect command1's output to command2's input. I've made some progress using named pipes, but POSIX::mkfifo is not cross-platform.

Here's part of what I have so far (the run method at the bottom basically calls 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;
}

#...

My specific questions:

  1. Is there an alternative to POSIX::mkfifo that is cross-platform? Win32 named pipes don't work, as you can't open those as regular files, neither do sockets, for the same reasons.

    2. The above doesn't quite work; the two threads get spawned correctly, but nothing flows across the pipe. I suppose that might have something to do with pipe deadlocking or output buffering. What throws me off is that when I run those two commands in the actual shell, everything works as expected.

Point 2 is solved; a -p fifo file test was not testing the correct file.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小帐篷 2024-09-10 02:56:31

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

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

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

...应该按您的预期工作, Linux 或 Windows。

Out of interest, why do you need a FIFO? Couldn't you just set up a regular pipe (e.g. with pipe?) And why use threads when you can use the much more strongly supported fork?

In fact, you could instead use a CPAN module to do most of your work for you. IPC::Run for example:

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

...should work as you expect, on Linux or Windows.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文