Perl Fork не работает должным образом при удаленном запуске (через SSH) - PullRequest
5 голосов
/ 23 июня 2010

У меня есть Perl-скрипт, script.pl, который при запуске делает форк, родительский процесс выводит свой 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.

Сценарий распечатывает некоторые вещи, а затем возвращает управление обратно в оболочку.(в то время как дочерний процесс уходит в свой цикл в фоновом режиме).

Однако, когда я вызываю это через ssh, управление никогда не возвращается обратно в оболочку (и при этом строка «Вывод запущен» никогда не печатается.

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

Однако интересно то, что дочерний процесс действительно запускается (я вижу это, когда набираю ps).

Может кто-нибудь объяснить, что происходит?

РЕДАКТИРОВАТЬ:

Я запустил его в режиме отладки и получил это:

### Раздвоенный, но не знаю, как создатьновый TTY.

Поскольку два отладчика борются за один и тот же TTY, ввод сильно запутан.

Я знаю, как переключить вывод в другое окно только на консолях xterms и OS / 2. Для руководствапереключите, поместите имя созданного TTY в $ DB :: fork_TTY или определите функцию DB :: get_fork_TTY (), возвращающую это.

В UNIX-подобных системах можно получить имя TTY длязаданное окно, набрав tty, и отключите оболочку от TTY с помощью sleep 1000000.

Ответы [ 3 ]

9 голосов
/ 23 июня 2010

Каждый раз, когда вы запускаете фоновые задания с помощью неинтерактивных команд ssh, вам необходимо закрыть или иным образом связать stdin, stdout и & stderr. В противном случае ssh будет ожидать завершения фонового процесса. FAQ .

Это называется разъединением или отсоединением от управляющего терминала и является общей рекомендацией при написании фоновых заданий, а не только для SSH.

Итак, самое простое изменение, которое не отключает всю вашу команду, - это добавить:

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

сразу после вашего print "Output started";. Если вашему дочернему процессу необходимо периодически печатать вывод во время своего запуска, вам нужно будет вместо этого перенаправить его в файл журнала.

4 голосов
/ 23 июня 2010

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

Вы не можете выйти, потому что процесс еще прикреплен. Вам нужно nohup это.

2 голосов
/ 23 июня 2010

То, что происходит, - то, что ssh непосредственно выполняет 'perl script.pl' как команду.Если у вас есть доступный «экран», вы можете сделать:

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

, чтобы он работал на отдельном экране, и подключить его позже с помощью screen -r

...