perl在退出时挂起(关闭文件句柄后)

vir*_*tor 3 linux perl ipc pipe process

我有一个功能(简而言之):

my $file = IO::File->new("| some_command >> /dev/null 2>&1") 
    or die "cannot open some_command for writing: $!\n";
...
undef $file;
Run Code Online (Sandbox Code Playgroud)

现在我甚至都没有写任何东西$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 ...>
Run Code Online (Sandbox Code Playgroud)

如果我打开相同的阅读过程,我不会看到这个问题.

要使程序退出,我该怎么办?

编辑:到目前为止的建议是使用Expect库或通过ctrl + d完成输入流.但是我现在不想以任何方式与该程序进行交互.我希望它现在完全没有任何更多的IO继续完成.那可能吗?

mob*_*mob 9

undef $file从文件句柄中删除引用计数,使其符合垃圾回收的条件.如果$file是常规文件的句柄,并且在其他任何地方都没有对文件句柄的其他引用,那么它应该按照文档中的说明工作IO::File.在这种情况下$file是shell命令的句柄,并且可能存在对文件句柄的一些其他内部引用,以防止它被销毁.使用$file->close更安全,使您的意图更清晰.


要在关闭文件句柄时终止命令不起作用,您需要进程ID.如果你调用了这样的命令

my ($file,$pid);
$pid = open($file, "| some_command >> /dev/null 2>&1");
Run Code Online (Sandbox Code Playgroud)

那么你可以

kill 'TERM',$pid;
Run Code Online (Sandbox Code Playgroud)

在你的程序结束时.我不知道如何从返回值中提取进程ID IO::File::new.


Dar*_*nke 6

如果some_command正在等待输入,它可能会永远坐在那里等待输入.

从文档的内容来看,我认为它没有任何区别,但我总是在取消句柄之前执行$ file-> close()而不是/.

编辑:发送它控制D?也许some_command正在读取tty而不是stdin,就像passwd那样.如果你在那个领域,我建议你查看Expect.

控制D只是复制了关闭应该对命令行程序执行的零字节读取.

您是否尝试过使用$ file-> close()而不是undef?