Perl: после успешного вызова системы команда "или умереть" все еще заканчивается script

Я использую следующую строку, чтобы сделать простой системный вызов, который работает:

system ("mkdir -p Purged") or die "Failed to mkdir." ;

Выполнение сценария действительно вызывает системный вызов, и я могу найти каталог с именем Purged, но сообщение об ошибке все еще печатается, и сценарий умирает. Что не так с моим синтаксисом?

Ответ 1

Это было бы немного запутанно, не так ли? - Леонардо Эррера на Икегами ответит

Да, сбивает с толку то, что system команда инвертирует true и false в Perl и создает забавную логику, например:

if ( system qw($command) ) {
    die qq(Aw... If failed);
}
else {
    say qq(Hooray! It worked!);
}

Но понятно, почему system команда делает это. В Unix нулевое состояние завершения означает, что программа работала, а ненулевое состояние может дать вам информацию о том, почему произошел сбой вашего system вызова. Возможно, программа, которую вы вызывали, не существует. Может быть, программа работает так, как ожидалось. Например, grep возвращает код выхода 1 когда работает grep, но не было соответствующих строк. Возможно, вы захотите различить, когда grep возвращает ноль, единицу или код возврата больше единицы. (Да, я знаю, что глупо использовать системный вызов grep в программе на Perl, но это первый пример, который я могу придумать).

Чтобы избежать случайной путаницы, я создаю переменную, в которой хранится состояние выхода моей system команды, вместо того, чтобы напрямую проверять вывод system:

my $error = system qw($command);
if ($error) {
    die qq(Aw... It failed);
}
else {
    say qq(Hooray! It worked!);
}

Это совершенно не нужно, и люди, работающие с Perl, должны знать, что system меняет определение Perl на true и false, но если я не выпил свой кофе по утрам, я могу пропустить его, когда просматриваю чужой код. Выполнение этого небольшого шага просто делает программу более логичной.

Perldoc системы дает вам код, который позволяет вам проверить вывод вашей системной команды, чтобы увидеть, что именно произошло. (Если произошла ошибка или сигнал системного прерывания прервал system вызов). Приятно знать, нужно ли запрашивать возвращаемое значение в вашей system чтобы выяснить, что пошло не так.

Ответ 2

system возвращает статус выхода команды, которую он вызывает. В оболочке нулевой статус выхода означает успех. Вы должны инвертировать логику:

0 == system qw(mkdir -p Purged) or die "Failed to create the dir\n";

Ответ 3

system возвращает 0 при успехе, поэтому вы хотите and, а не or.

См. также: use autodie qw( system );

Ответ 4

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

system возврат 'zero-or-not' только сообщает, была ли команда выполнена успешно, shell или execvp; 0 не означает, что команда преуспела в том, что она делала.

В случае ненулевого возврата вам нужно распаковать $? для дополнительной информации; см. систему, как это сделать. Например, фактический код завершения команды $? >> 8 $? >> 8, о чем исполняемая программа была предназначена для сообщения на выходе.

В целом вы можете сделать что-то с эффектом

sub run_system {
    my ($cmd, @other_agrs) = @_;             # may do more via @other_args

    my ($cmdref, $sys_ret) = (ref $cmd, 0);  # LIST or scalar invocation?
    if ($cmdref eq 'ARRAY') {
        $sys_ret = system(@$cmd);
    }
    elsif (not $cmdref) {
        $sys_ret = system($cmd);
    }
    else { Carp::carp "Invocation error, got $cmdref" }

    return 1 if $sys_ret == 0;

    # Still here? The rest is error handling.
    Carp::carp "Trouble with 'system($cmd)': $?";
    print "Got exit " . ($? >> 8) . " from $cmd\n";
    return 0;  # or die (but then design changes)
}

Это можно сделать просто как system == 0 or do {... }; или прямо в коде, но таким образом есть небольшая библиотека, где мы можем более легко улучшить обработку ошибок, в конечном итоге принять решение переключиться на модуль для управления внешними командами и т.д. Кроме того, будучи средством на уровне пользователя, теперь имеет смысл что он возвращает истину в случае успеха (мы не меняем дизайн system).

Кроме того, в этом случае mkdir -p должен быть тихим, и в некоторых случаях он может ничего не говорить, если не может выполнить свою работу. Конечно, это так, но об этом нужно знать.

Ответ 5

Однострочное решение:

system("if printf '' > tmp.txt; then exit 1; else exit 0; fi ;") or die("unable to clobber tmp.txt");