Вопрос по exit-code, perl – Perl: получение правильного возвращаемого значения из команды 'system'

5

Я начинающий в Perl. У меня есть пакетный скрипт Windows, который содержит несколько команд NMake. Существующая проблема с этим пакетным сценарием заключается в том, что даже если команда NMake завершится с ошибкой во время ее выполнения,ERRORLEVEL неправильно настроен.

Поэтому мы никогда не узнаем, сработала ли команда, пока не проанализируем файл журнала. Я изучил это, но не смог найти решение. Затем я подумал о преобразовании этого пакетного сценария в сценарий Perl, предполагая, что ошибка перехвата будет легче, но кажется, что это не так просто :)

Всякий раз, когда я запускаю свой Perl-скрипт, «система» команда всегда возвращает 0. Я просмотрел много разных ссылок и понял, что получение правильного статуса возврата «системы» Команда не так проста. Тем не менее, я попробовал предложения, но все не работает. :(

Позвольте мне упомянуть, что вызываемая команда NMake, в свою очередь, вызывает много разных команд во время ее выполнения. Например, упомянутый ниже вывод команды, который выдает «фатальную ошибку», фактически является частью сценария Perl (check_dir.pl). Этот вызов Perl-скрипта записан в самом файле NMake.

Если я называю этот файл Perl (check_dir.pl) directly и проверить выходное значение, я получаю правильный результат, то есть команда завершается неудачно и печатаетnon-zero выходное значение (...unexpectedly returned exit value 2).

Пробовал системную функцию Perl, но это не помогло. Я использовал следующий код:

<code>system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");

if ( $? == -1 ) {
    print "Command failed to execute: $!\n";
}
elsif ( $? & 127 ) {
    printf "The child died with signal %d, %s a coredump\n",
    ( $? & 127 ), ( $? & 128 ) ? 'with' : 'without';
}
else {
    printf "child exited with value %d\n", $? >> 8;
}
</code>

Выход:

.....  
.....  
Unable to open dir: R:\TSM_Latest  
Compressing...NMAKE : fatal error U1077: 'if' : return code '0x2'  
Stop.  
child exited with value 0

Также попробовал:

<code>use IPC::System::Simple qw(system);  
my $exit_status = system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");

if ($exit_status != 0) {  
    print "Failure";  
    exit 3;  
} else {  
    print "Success";  
}
</code>

Наконец-то попробовал следующий модуль:

<code>use IPC::Run qw( run timeout );  
run "nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1" or die "NMake returned $?";
</code>

Кажется, ничего не работает :(

Пожалуйста, исправьте меня, если я интерпретирую возвращаемое значениеsystem неправильно.

Ваш Ответ

1   ответ
7

У тебя есть:

use IPC::System::Simple qw(system);
my $exit_status = system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");

Учитывая, что вы, похоже, не заботитесь о фактических результатах, вы можете попробовать

my $exit_status = systemx(nmake => 
                              qw(/f _nt.mak pack_cd),
                              "SUB_PLAT=$PLAT",
                              "DR=$plat",
                          );

Чтобы убедиться, что вы обходитеcmd.exe и посмотрим, получишь ли ты что-нибудь полезное.

Для справки,коды выхода из nmake перечислены здесь.

Запускаем следующую программу:

use strict; use warnings;

use IPC::System::Simple qw(systemx);
use Try::Tiny;

my $status = 0;

try   { systemx nmake => qw(/f bogus) }
catch { ($status) = ( /exit value ([0-9])/ ) };

print "Failed to execute nmake. Exit status = $status\n";

производит:

NMAKE : fatal error U1052: file 'bogus' not found
Stop.
Failed to execute nmake. Exit status = 2

Следующая версия:

use strict; use warnings;

my $status = system nmake => qw(/f bogus);

if ($status) {
    if ($? == -1) {
        print "failed to execute: $!\n";
    }
    elsif ($? & 127) {
        printf "child died with signal %d, %s coredump\n",
        ($? & 127), ($? & 128) ? 'with' : 'without';
    }
    else {
        printf "child exited with value %d\n", $? >> 8;
    }
}

производит:

NMAKE : fatal error U1052: file 'bogus' not found
Stop.
child exited with value 2

На самом деле, даже когда я использую

my $status = system "nmake /f bogus";

Я получаю такой же правильный и ожидаемый результат.

То же самое, когда я использую

my $status = system "nmake /f bogus 2>&1";

Эти наблюдения приводят меня к следующим вопросам:

  1. Which version of nmake are you using?

  2. Is the /I option in effect? Even though you don't set it from the command line, note the following:

/I Ignores exit codes from all commands. To set or clear /I for part of a makefile, use !CMDSWITCHES. To ignore exit codes for part of a makefile, use a dash () command modifier or .IGNORE. Overrides /K if both are specified.

Итак, я собрал следующие файлы:

C:\temp> cat test.mak
test.target: bogus.pl; perl bogus.pl
C:\temp> cat bogus.pl
exit 1;

И побежал:

use strict; use warnings;

my $status = system "nmake /f test.mak 2>&1";

if ($status) {
    if ($? == -1) {
        print "failed to execute: $!\n";
    }
    elsif ($? & 127) {
        printf "child died with signal %d, %s coredump\n",
        ($? & 127), ($? & 128) ? 'with' : 'without';
    }
    else {
        printf "child exited with value %d\n", $? >> 8;
    }
}

который дал мне вывод:

        perl bogus.pl
NMAKE : fatal error U1077: 'c:\opt\perl\bin\perl.EXE' : return code '0x1'
Stop.
child exited with value 2

где последняя строка показывает, что состояние выхода nmake было правильно передано.

Conclusion:

You have some other problem.

Фактически, ФП позже указал в комментариях, что:

The actual command that i am trying to run is: system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1 | C:\\tee2 $TEMP_DIR\\modules-nt_${platlogfile}");

Даноteeс участием в трубопроводе, это не удивительно, чтоnmakeКод выхода s теряется.tee успешно может обрабатывать вывод изnmakeон возвращает успех, и это код выхода, который видит ваш скрипт.

Таким образом, решение состоит в том, чтобы захватить выводnmake себя, либо используяqx (в сочетании с соответствующим уровнем проверки ошибок), или используяcapture отIPC::System::Simple, Затем вы можете решить, хотите ли вы распечатать этот вывод, сохранить в файл, поместить его в электронное письмо и т. Д. & # X2026;

Большое спасибо за указатели! Я проверюqx а такжеcapture Technext
Кажетсяtee Команда всегда была успешной, поэтому возвращаемое значение всегда было 0. Я прав? Теперь, когда я запускаю свою исходную команду, используя «систему», она работает как положено:use IPC::System::Simple qw(system); system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat > $TEMP_DIR\\modules-nt_${platlogfile}");    Теперь единственная проблема, с которой я сталкиваюсь, заключается в том, что я не вижу никаких выходных данных консоли, потому что все перенаправляется в файл. Любая помощь в этом отношении? Technext
вы можете привязать лог-файл к отдельному процессу или потоку perl. Я не знаю, возможно ли это простым способом на окнах.
Спасибо за вашу помощь, Синан! Первый системный код, который вы попросили меня протестировать (в обход cmd.exe), работал нормально. Однако тогда я понял, что я сделал. Фактическая команда, которую я пытаюсь выполнить:system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1 | C:\\tee2 $TEMP_DIR\\modules-nt_${platlogfile}");     и неsystem ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");    Вчера я случайно удалил часть регистрации («pipe»), думая, что я должен только опубликовать соответствующий код. Я & APOS; мreally простите за этот синан! :( Technext

Похожие вопросы