我有一个功能(简而言之):
my $file = IO::File->new("| some_command >> /dev/null 2>&1")
or die "cannot open some_command for writing: $!\n";
...
undef $file;
现在我甚至都没有给$file
写任何东西。目前,$file
上根本没有其他操作。当我运行该程序时,它无法正常退出。我看到句柄已关闭,但我的程序仍在等待关闭进程。使用strace
捕获:
close(6) = 0
rt_sigaction(SIGHUP, {SIG_IGN}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGINT, {SIG_IGN}, {SIG_DFL}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_IGN}, {SIG_DFL}, 8) = 0
wait4(16861, ^C <unfinished ...>
如果我打开相同的阅读流程,我不会看到这个问题。
如何让程序退出?
编辑:到目前为止的建议是使用Expect库或通过ctrl + d完成输入流。但是我现在不想以任何方式与该程序进行交互。我希望它完全现在完成,而不再进行任何IO。这可能吗?
答案 0 :(得分:9)
undef $file
从文件句柄中删除引用计数,并使其符合垃圾回收的条件。如果$file
是常规文件的句柄,并且在其他任何地方都没有对文件句柄的其他引用,则它应该按照IO::File
中的说明进行操作。在这种情况下,$file
是shell命令的句柄,并且可能存在对文件句柄的一些其他内部引用,以防止它被销毁。使用$file->close
更安全,使您的意图更加清晰。
<小时/>
要在关闭文件句柄时终止命令不起作用,您需要进程ID。如果你调用了像
这样的命令my ($file,$pid);
$pid = open($file, "| some_command >> /dev/null 2>&1");
然后你可以
kill 'TERM',$pid;
在您的计划结束时。我不知道如何从IO::File::new
的返回值中提取进程ID。
答案 1 :(得分:6)
如果some_command正在等待输入,它可能会永远坐在那里等待输入。
从文档的内容来看,我认为它没有任何区别,但我总是在取消处理句柄之前执行$ file-&gt; close()而不是/。
编辑:发送它控制D? 也许some_command正在读取tty而不是stdin,就像passwd那样。如果你在那个领域,我建议你查看Expect。
控制D只是复制了关闭应该对命令行程序执行的零字节读取。
您是否尝试使用$ file-&gt; close()而不是undef?
答案 2 :(得分:0)
some_command是否会输入并处理它?比如grep? 还是提示?比如说... chfn? 它是否返回任何有用的信息?就像它已经完成的迹象一样?
如果是后者,您可能需要阅读Expect,以便您可以与之互动。
答案 3 :(得分:0)
这个丑陋,丑陋的黑客攻击会导致some_command
成为init
的父级,而不是留在perl
的进程树中。 Perl不再需要等待任何进程,并且管道仍然有效 - yay UNIX。
my $file = IO::File->new("| some_command >> /dev/null 2>&1 &")
缺点:即使&
失败,shell也会在some_command
成功,因此您不会再收到任何错误。
or die "cannot open some_command for writing: $!\n"; # now useless
如果some_command
在stdin上获得EOF后立即退出(并且永远不会停止从stdin读取),但我希望这不是必需的。
$ cat | some_command ^D
那会挂起吗,你可以解决这个问题吗?