Как правильно выполнить этот системный вызов, подверженный ошибкам, в perl? - PullRequest
2 голосов
/ 27 августа 2010

Поэтому, как часть сценария запуска для компьютерных лабораторных систем OS X, я запускаю встроенную команду оболочки, называемую systemsetup, для синхронизации системы с сетевым сервером времени. Он работает внутри сценария Perl следующим образом.

#!/usr/bin/perl

system("systemsetup -setusingnetworktime off");
system("systemsetup -setusingnetworktime on");

Если сначала включить его, то он будет обновляться при включении.

Проблема в том, что очень часто эта команда выдает следующую ошибку writeconfig[1841:903] *** -[NSMachPort handlePortMessage:]: dropping incoming DO message because the connection or ports are invalid, а затем останавливает выполнение оболочки или сценария в зависимости от того, где я ее запускаю.

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

Итак, я понимаю, что это довольно очевидная ошибка в systemsetup, из-за которой выдается эта ошибка, но я уверен, что есть способ заставить мой скрипт perl изящно его обработать, верно?

Лучшее, что у меня есть на данный момент, это systemsetup -setusingnetworktime off&>/dev/null, который передает STDOUT и STDERR в /dev/null.

.

Ответы [ 2 ]

6 голосов
/ 27 августа 2010

Если команда может выйти из строя и повесить ваш скрипт, хорошей защитой будет использование alarm и обработчика SIGALRM для истечения времени ожидания команды.

sub system_with_timeout {
    my ($timeout, @command) = @_;
    local $SIG{ALRM} = sub { die "Timeout\n" };
    my $result;
    if ($timeout > 0) { alarm $timeout; }
    eval {
        $result = system(@command);
    };
    if ($@ =~ /Timeout/) {
        warn "@command timed out.\n";
        return -1;
    }
    return $result;
}

Проверьте возвращаемые значения, чтобы убедиться, что ваша команда была успешной или истекла ли она.

my $z = system_with_timeout(30, "systemsetup -setusingnetworktime off");
if ($z == 0) {
    # success ...
} elsif ($z == -1) {
    # timed out ... try it again ?
} else {
    # failed for some other reason ...
}
2 голосов
/ 27 августа 2010

Если вас не волнует сама ошибка (например, это просто предупреждающее сообщение), непременно перенаправьте STDOUT / STDERR команды;хотя я лично рекомендую перенаправить файл журнала / tmp (а не /dev/null) на тот случай, если вам когда-нибудь понадобится устранить некоторые ДРУГИЕ ошибки.

Если вы действительно хотите предпринять конкретные действия при такомошибка, вы можете либо проверить код возврата (см. ответ mobrule), либо, если команда всегда возвращает 0, захватить результаты и отфильтровать их на предмет ошибки:

my @script_out = `systemsetup -setusingnetworktime off`;
# better yet use open with a pipe instead of backticks 
if (grep {/writeconfig.*dropping incoming DO message/} @script_out {
    # do error handling
}
...