В Perl есть ли способ перезапустить программу, запущенную в настоящее время изнутри?

Я запускаю программу в Perl, которая в какой-то момент оценивает данные в операторе if, вызываемом из подпрограммы, например

sub check_good {
    if (!good) {
         # exit this subroutine
         # restart program
    } 
    else {
         # keep going
    }
} # end sub

проблема у меня есть с выходом и перезапуском. Я знаю, что могу просто использовать exit 0; чтобы выйти прямо, но, очевидно, это неправильно, если я хочу вернуться к началу. Я попытался вызвать подпрограмму, которая по существу запускает программу, но, конечно, после ее запуска она снова вернется к этой точке. Я думал о поместить его в цикл while, но это означало бы поместить весь файл в цикл, и это было бы очень непрактично.

Я на самом деле не знаю, возможно ли это, поэтому любой вход будет отличным.

3 ответов


если вы не меняли @ARGV, или вы держите его копию, вы могли бы сделать что-то вроде exec($^X, , @ARGV).

$^X и (или $EXECUTABLE_NAME и $PROGRAM_NAME, см. комментарий Брайана ниже) являются текущим интерпретатором perl и текущим скриптом perl соответственно.


альтернативой было бы всегда иметь два процесса: супервизор и работник.

рефакторинг всей вашей логики в подпрограмму под названием run(или main или любой другой). Whn ваша реальная логика обнаруживает, что ей нужно перезапустить, она должна выйти с предопределенным ненулевым кодом выхода (например, 1).

тогда ваш основной скрипт и супервизор будут выглядеть так:

if (my $worker = fork) {
    # child process
    run(@ARGV);
    exit 0;
}
# supervisor process
waitpid $worker;
my $status = ($? >> 8);

if ($status == 1) { ... restart .. }

exit $status; # propagate exit code...

в простом сценарии, где вы просто хотите перезапустить один раз, это может быть немного перебор. Но если вам в любой момент нужно иметь возможность обрабатывать другие сценарии ошибок, этот метод может быть предпочтительным.

например, если код выхода равен 255, это означает, что основной скрипт называется die(). В этом случае может потребоваться реализовать некоторую процедуру принятия решения для перезапуска сценария, игнорирования ошибки или эскалации проблемы.

существует довольно много модулей по CPAN, реализующих таких супервизоров. Proc:: Launcher один из них и на странице руководства подробно обсуждаются соответствующие работы. (Я никогда не использовал Proc::Launcher, в основном из-за этого обсуждения я ссылаюсь на него)


ничто не мешает тебе называть system на себя. Что-то вроде этого (явно нуждается в аккуратности), где я передаю аргумент командной строки, чтобы предотвратить вызов кода навсегда.

#!/usr/bin/perl
use strict;
use warnings;

print "Starting...\n";
sleep 5;

if (! @ARGV) {
        print "Start myself again...\n";
        system("./sleep.pl secondgo");
        print "...and die now\n";
        exit;
} elsif ((@ARGV) && $ARGV[0] eq "secondgo") {
        print "Just going to die straightaway this time\n";
        exit;
}