【问题标题】:perl hangs on exit (after closing a filehandle)perl 在退出时挂起(关闭文件句柄后)
【发布时间】:2010-12-07 10:24:11
【问题描述】:

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

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。这可能吗?

【问题讨论】:

  • 你到底想达到什么目的?
  • 好吧 - 我只是想让程序退出 ;) - 到目前为止它只是挂在 wait4() 调用上。
  • 您可能想要关闭文件,而不是取消定义它。 $file-&gt;close
  • undef 根据 perldoc 关闭文件。 strace 输出中还有一个 close(6) 。 (显式 -&gt;close() 也没有改变任何东西,试过了)
  • 我了解到您希望程序退出。你的程序的总体目的是什么?答案取决于那个目的以及some_command 的作用。

标签: linux perl process ipc pipe


【解决方案1】:

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


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

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

那么你可以

kill 'TERM',$pid;

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

【讨论】:

    【解决方案2】:

    如果 some_command 正在等待输入,它可能会一直坐在那里等待输入。

    根据文档所说,我认为这没有任何区别,但我总是使用 $file->close() 而不是取消定义句柄之前/之前。

    编辑:发送控制 D? 也许 some_command 正在读取 tty 而不是 stdin,就像 passwd 一样。如果您处于该领域,我建议您查找 Expect。

    Control D 只是复制了 close 对命令行程序无论如何都应该执行的零字节读取。

    你试过用 $file->close() 代替 undef 吗?

    【讨论】:

    • 是的,它确实在等待输入。如果只有该文件句柄可用,如何确保程序关闭?
    • 确实有提示。而且我不想要/不需要expect 功能。我想简单地强制该过程退出。我不想向进程发送任何内容,因为我不知道它处于什么状态(因此 CTRL+d 会做什么)。我可以终止该进程,并且不希望它在那时进行任何处理。
    • 只是更具体地说-如果进程被杀死,那将是完美的。当我的程序的管道断开时,我不希望它以任何方式运行。
    【解决方案3】:

    some_command 是否会吞下所有输入并进行处理?比如grep? 还是提示?比如,说... chfn? 它是否返回任何有用的信息?就像它已经完成的迹象?

    如果是后者,您可能需要阅读 Expect 以便与它互动。

    【讨论】:

    • 确实有提示。而且我不想要/不需要expect 功能。我想简单地强制该进程退出。
    【解决方案4】:

    这个丑陋、丑陋的 hack 将导致 some_command 成为 init 的父级,而不是留在您的 perl 的进程树中。 Perl 不再需要等待任何进程,并且管道仍然可以工作——是的 UNIX。

    my $file = IO::File->new("| some_command >> /dev/null 2>&1 &")
    

    缺点:即使some_command 失败,shell 也会在&amp; 处成功,因此不会返回任何错误。

        or die "cannot open some_command for writing: $!\n";  # now useless
    

    如果some_command 在 stdin 上获得 EOF 后立即退出(并且永远不会停止从 stdin 读取),我希望这没有必要。

    $ 猫 |一些命令 ^D

    这会挂起吗,你能解决它吗?

    【讨论】:

      猜你喜欢
      • 2011-08-16
      • 1970-01-01
      • 2011-07-23
      • 2013-11-30
      • 1970-01-01
      • 2015-04-13
      • 2012-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多