【问题标题】:perl fork doesn't work properly when run remotely (via ssh)perl fork 远程运行时无法正常工作(通过 ssh)
【发布时间】:2011-03-07 00:58:51
【问题描述】:

我有一个 perl 脚本 script.pl,它在运行时会执行 fork,父进程将其 pid 输出到文件然后退出,而子进程将某些内容输出到 STOUT,然后进入 while 循环。

$pid = fork();

if ( ! defined $pid ) 
{
    die "Failed to fork.";
}
#Parent process
elsif($pid)
{
    if(!open (PID, ">>running_PIDs"))
    {
        warn "Error opening file to append PID";
    }
    print PID "$pid  \n";
    close PID;
}
#child process
else
{
    print "Output started";

    while($loopControl)     
    {
           #Do some stuff
    }
}

当我在本地调用它时效果很好,即:perl script.pl。

脚本打印出一些内容,然后将控制权返回给 shell。 (而子进程在后台进入其循环)。

但是,当我通过 ssh 调用它时,控制永远不会返回到 shell(也不会打印“输出开始”行。

即: $ ssh username@example.com 'perl script.pl'

然而,有趣的是,子进程确实在运行(我可以在输入 ps 时看到它)。

谁能解释这是怎么回事?

编辑:

我在调试下运行它并得到了这个:

### forked,但不知道如何创建新的 TTY。

由于两个调试器争夺同一个 TTY,输入严重纠缠。

我知道如何在 xterms 中将输出切换到不同的窗口 和 OS/2 控制台。对于手动切换,输入创建的 TTY 的名称 在 $DB::fork_TTY 中,或者定义一个返回 this 的函数 DB::get_fork_TTY()。

在类 UNIX 系统上,可以获取给定窗口的 TTY 名称 通过键入 tty,然后通过 sleep 1000000 断开 shell 与 TTY 的连接。

【问题讨论】:

  • 如果除了screen(我并不总是有)之外,还有其他人对此问题有解决方案,我很乐意看到它。

标签: perl unix ssh fork


【解决方案1】:

当您通过非交互式 ssh 命令启动后台作业时,您需要关闭或以其他方式绑定 stdin、stdout 和 stderr。否则 ssh 将等待后台进程退出。 FAQ.

这称为与控制终端解除关联或分离,是编写后台作业时的一般最佳实践,而不仅仅是 SSH。

因此,不会使整个命令静音的最简单更改是添加:

#close std fds inherited from parent
close STDIN;
close STDOUT;
close STDERR;

就在您的print "Output started"; 之后。如果您的子进程需要在运行期间定期打印输出,那么您需要重定向到日志文件。

【讨论】:

  • 在阅读您的帖子之前浪费了数小时进行调试。谢谢,它有效!
【解决方案2】:

ssh username@example.com 'nohup perl script.pl'

您无法退出,因为仍有一个附加进程。你需要nohup它。

【讨论】:

  • 好像没有效果。 =[
【解决方案3】:

发生的事情是 ssh 直接将“perl script.pl”作为命令执行。如果您有可用的“屏幕”,您可以这样做:

$ ssh username@example.com 'screen -d -m perl script.pl'

让它在分离的屏幕上运行,稍后使用 screen -r 重新连接

【讨论】:

  • 这有效,控制权被返回。通过 ssh 远程运行它与在本地运行它有什么不同呢?怎么在本地就没有问题了?
  • @Razor,远程运行时,没有外壳——另一端的 ssh 守护进程运行并将自身附加到脚本。你也可以通过运行bash -c "perl script.pl" 作为 ssh 命令来实现你想要的
  • 但是,父进程结束了,那么附加的守护进程不应该也停止运行吗?
【解决方案4】:

为了更好地理解这一点,我建议阅读@Jax 的解决方案

Getting ssh to execute a command in the background on target machine

这与 Perl 无关。这是因为 SSH 处理您尝试在后台运行的任何长时间运行的进程的方式。

我需要从 bash 脚本启动 script.pl(在目标主机上定义必要的局部变量):

$ ssh username@example.com /path/to/launcher.sh

/path/to/launcher.sh 正在调用 Perl 脚本:

CMD="/path/to/script.pl -some_arg=$VALUE -other_arg"
$CMD &

在本地工作,但通过 ssh 运行时没有返回。

我在 Perl 脚本中尝试了@pra 的解决方案,但在我的情况下不起作用。

使用@Jax 的解决方案,我将$CMD & 替换为:

nohup $CMD > /path/to/output.log 2>&1 < /dev/null &

而且效果很好。

【讨论】:

    猜你喜欢
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    相关资源
    最近更新 更多