Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
perl中管道文件句柄的问题_Perl_Pipe_Filehandle - Fatal编程技术网

perl中管道文件句柄的问题

perl中管道文件句柄的问题,perl,pipe,filehandle,Perl,Pipe,Filehandle,我试图从另一个perl脚本运行bp\u genbank2gff3.pl(bioperl包),该脚本 获取一个genbank作为其参数 这不起作用(未生成输出文件): 但这是真的 open( my $command_out, "-|", $command ); sleep 3; # why do I need to sleep? close $command_out; 为什么? 我认为close应该在命令完成之前阻塞: 关闭任何管道文件句柄会导致 父进程等待 要完成的孩子。。。

我试图从另一个perl脚本运行
bp\u genbank2gff3.pl
(bioperl包),该脚本 获取一个genbank作为其参数

这不起作用(未生成输出文件):

但这是真的

   open( my $command_out, "-|", $command );
   sleep 3; # why do I need to sleep?
   close $command_out;
为什么?

我认为
close
应该在命令完成之前阻塞:

关闭任何管道文件句柄会导致 父进程等待 要完成的孩子。。。 (见附件)

编辑

我将此添加为最后一行:

say "ret=$ret, \$?=$?, \$!=$!";
在这两种情况下,打印输出为:

ret=, $?=13, $!=

(这意味着在这两种情况下关闭都失败了,对吗?

我不确定你想做什么,但在这种情况下可能更好…

$?=13
表示您的子进程被信号终止。您的外部程序(
bp_genbank2gff3.pl
)试图将一些输出写入管道到
perl
程序。但是
perl
程序关闭了管道末端,因此您的操作系统向外部程序发送了一个
SIGPIPE

通过
sleep
ing 3秒钟,您可以让您的程序在操作系统杀死它之前运行3秒钟,这样可以让您的程序完成一些事情。但是请注意,管道的容量有限,因此,如果您的父
perl
脚本没有从管道中读取数据,并且如果外部程序正在向标准输出写入大量数据,那么外部程序的写入操作最终将阻塞,您可能无法从外部程序中获得3秒钟的工作时间

解决方法是读取外部程序的输出,即使您只是将其扔掉

open( my $command_out, "-|", $command );
my @ignore_me = <$command_out>;
close $command_out;
当然,如果您要费那么大的劲忽略输出,您也可以使用
system



附加信息:正如OP所说,关闭管道文件句柄会导致父级等待子级完成(通过使用
waitpid
或类似方法)。但在它开始等待之前,它关闭了管道的末端。在本例中,该端是子进程将其标准输出写入的管道的读取端。下一次,当子进程尝试向标准输出写入内容时,操作系统检测到该管道的读取端已关闭,并向子进程发送一个
SIGPIPE
,杀死它并快速让父进程中的
close
语句完成。

我使用
open
,因为我想动态读取命令stdout,据我所知,使用
system
无法完成(
system
等待命令完成,然后立即返回所有输出)。上面的例子只是一个简化的版本,不包括这一部分,但它对问题无关紧要。好的,所以在打开和关闭之间需要一个“while(){do stuff}”,这是我正在使用的一个通用方法。因此,有时我确实想用命令发送给stdout的内容来处理一些事情,然后我真的按照您的建议使用
while
。但是如果我没有,为什么命令不能正确执行呢?例如,我们在这里讨论的命令获取某种格式的文件名,然后将其数据拆分为两个不同格式的文件。它生成文件并将一些日志消息打印到标准输出。在这种情况下,我不关心stdout,所以我暂时不用它。这有什么关系呢?
close()
的返回值是多少?什么是
$?
也许还有
$?是
bp\u genbank2gff3.pl
,还是
$ARGV[0]
的shell扩展分叉并退出?
strace
truss
说发生了什么?您确定“正在工作”案例中的输出文件不是无关的成功作业遗留下来的吗?您是否可以使用一些常用的shell实用程序而不是
bp_…3.pl
?@pilcrow请参见编辑
strace
返回一个很长的列表,我应该查找什么?我确信当
sleep
处于打开状态时(我在运行之前删除了dir的全部内容),输出不是剩余的。我不明白你的问题,你是叉子。顺便说一句:
strace-fe trace=processmy_perl_脚本
应该可以让您开始。然而,@mobrule从
$?
中找到了答案。我没有得到什么。我的外部程序确实试图编写一些输出(比如开始时“处理…”,然后在结束时“完成”)。但是为什么你说的“perl程序结束了它的管道”?换句话说,到底为什么
my@ignore_me=这有什么不同吗?@David B-当一个进程(在本例中是您的孩子)写入读卡器(您的家长)已经关闭的管道时,您会得到一个
SIGPIPE
。我的书写
在父级中,您将保持管道的读取端打开,直到管道的写入端完成。它读取孩子试图写入的内容。这就不同了。通过不读取打开管道的程序的输出,您正在将水转向花园软管并堵住软管的尖端。如果您不想要程序的输出,请使用
system
.rule、@Sinan和@pilcrow-谢谢大家。这很有趣。
open( my $command_out, "-|", $command );
my @ignore_me = <$command_out>;
close $command_out;
open my $command_out, "-|", "$command > /dev/null";
close $command_out;     # succeeds, no SIGPIPE