【发布时间】:2020-07-05 07:53:25
【问题描述】:
Perl 程序使用IPC::Run 将文件通过在运行时确定的一系列命令传递到另一个文件中,就像这个小测试摘录所示:
#!/usr/bin/perl
use IO::File;
use IPC::Run qw(run);
open (my $in, 'test.txt');
my $out = IO::File->new_tmpfile;
my @args = ( [ split / /, shift ], "<", $in); # this code
while ($#ARGV >= 0) { # extracted
push @args, "|", [ split / /, shift ]; # verbatim
} # from the
push @args, ">pipe", $out; # program
print "Running...";
run @args or die "command failed ($?)";
print "Done\n";
它从作为参数给出的命令构建管道,测试文件是硬编码的。问题是如果文件大于 64KiB,管道就会挂起。这是一个演示,它在管道中使用cat 以保持简单。首先一个 64KiB(65536 字节)的文件按预期工作:
$ dd if=/dev/urandom of=test.txt bs=1 count=65536
65536 bytes (66 kB, 64 KiB) copied, 0.16437 s, 399 kB/s
$ ./test.pl cat
Running...Done
接下来,再增加一个字节。对run 的调用永远不会返回...
$ dd if=/dev/urandom of=test.txt bs=1 count=65537
65537 bytes (66 kB, 64 KiB) copied, 0.151517 s, 433 kB/s
$ ./test.pl cat
Running...
启用IPCRUNDEBUG,再加上几只猫,您可以看到它是最后一个没有结束的孩子:
$ IPCRUNDEBUG=basic ./test.pl cat cat cat cat
Running...
...
IPC::Run 0000 [#1(3543608)]: kid 1 (3543609) exited
IPC::Run 0000 [#1(3543608)]: 3543609 returned 0
IPC::Run 0000 [#1(3543608)]: kid 2 (3543610) exited
IPC::Run 0000 [#1(3543608)]: 3543610 returned 0
IPC::Run 0000 [#1(3543608)]: kid 3 (3543611) exited
IPC::Run 0000 [#1(3543608)]: 3543611 returned 0
(对于 64KiB 以下的文件,您会看到所有四个都正常退出)
如何使它适用于任何大小的文件?
(Perl 5,版本 30,subversion 3 (v5.30.3) 为 x86_64-linux-thread-multi 构建,在目标平台 Alpine Linux 和 Arch Linux 上尝试排除 Alpine 的原因)
【问题讨论】:
-
提示:将
use IO::File; my $out = IO::File->new_tmpfile;(创建文件)替换为use Symbol qw( gensym ); my $out = gensym;(创建匿名glob)。创建文件后立即关闭它是没有意义的! -
@ikegami 实际程序中的文件没有关闭,但程序继续使用它。以上是一个最小的例子。还有 Håkon Hægland 我读过有关管道缓冲的文章,但我不明白当管道清空到文件中时它是如何应用的?
-
@starfry,用管道替换文件时被
run关闭。 -
Re “当管道清空到文件中时?”,管道不会清空任何内容。通过从管道中读取进程来读取/清空管道。
标签: perl ipc perl-ipc-run