Perl — $? показывает 0 для кода возврата -1 в 64-разрядной версии Windows 2008

#perl #system

#perl #система

Вопрос:

Использование Strawberry Perl 5.12.3

Запуск вручную:

 E:informaticatools>infacmd isp ping -sn tt -re 0
[ICMD_10033] Command [ping] failed with error [[INFACMD_10053] Service [tt] Domain [dmt3-9-dom-poc] has failed to ping back.].

E:informaticatools>echo %ERRORLEVEL%
-1
  

Когда я запускаю ту же команду через «систему» Perl, $? показывает 0. Код Perl:

 use strict;
use warnings;
my $cmd = system("infacmd isp ping -sn tt -re 0");
if ($? == -1) {        
    print "failed to execute: $!n";    
}    
elsif ($? amp; 127) {        
    printf "child died with signal %d, %s coredumpn", ($? amp; 127),  ($? amp; 128) ? 'with' : 'without';    
}    
else {        
    printf "child exited with value %dn", $? >> 8;    
}
  

Вывод:

 [ICMD_10033] Command [ping] failed with error [[INFACMD_10053] Service [tt] Domain     [dmt3-9-dom-poc] has failed to ping back.].
child exited with value 0
  

То же самое в 32-разрядной версии Windows 2003 и ActiveState Perl 5.8.8 показывает правильные результаты.

Комментарии:

1. Интересно, как это возможно, поскольку ExitThread и TerminateThread принимают целое число без знака .

Ответ №1:

Возможно, вам повезет больше с ${^CHILD_ERROR_NATIVE} , чем с эмуляцией структуры состояния процесса unix.

Комментарии:

1. Он также возвращает ноль. Я озадачен.

Ответ №2:

Я полагаю, что вашего ручного теста не совсем достаточно, поскольку переменная «errorlevel» может быть затенена или вопросы могут быть иным образом перепутаны использованием оболочки, поэтому ваш «infacmd» может завершаться не с тем кодом выхода, который вы считаете нужным.

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

т.е. если вы измените system строку на эту:

    my $cmd = system('infacmd', 'isp', 'ping', '-sn', 'tt', '-re', '0');
  

… влияет ли поведение вообще?

Комментарии:

1. Вопреки документации, использование формы списка не препятствует использованию оболочки в Windows. Тем не менее, он не будет использоваться в этом случае, если infacmd его можно запустить без командной строки.

2. Это очень полезная информация. Вы знаете, относится ли это конкретно к ActivePerl или это верно также для strawberry perl и msys perl?

3. @Friend-Pal, я полагаю, это влияет как на AP, так и на Strawberry, но не на cygwin. Попробуйте system("dir", "*") выяснить. В соответствии с документацией, должен произойти сбой.

4. @Friend-Pal, обратите внимание, что system({ 'dir' } 'dir', '*') происходит сбой, как и должно быть.

5. @Friend-Pal, я попробовал твое предложение, но оно не сработало. Тот же результат. На данный момент я не тестировал AP на Win2008, но AP на Win2003 возвращает 255, как и ожидалось.

Ответ №3:

Я думаю, вам следует сдвинуть $? (Т. Е. разделить его на 256), прежде чем выполнять переход…

 $res = $? >>8;
if ($res == -1)
....
  

Согласно определению системы в perlfunc

РЕДАКТИРОВАТЬ: я только что прочитал в perl 5 by examples (глава: обработка ошибок и сигналов), что в Windows вы не можете полагаться на $? Для представления состояния завершения каналов и системы. это вполне может быть вашим случаем.

тогда предлагается захватить вывод команды и проанализировать его, чтобы выяснить, какой код ошибки…

  my $output = `mycmd 2>amp;1`;
 if ($output =~ /.....
  

Комментарии:

1. хотя ваш ответ соответствует правилам perlfunc, IIRC, 0 / 256 == 0

2. Спасибо, ввод $?>> 8 перед if не сработал. В качестве последнего средства мне придется проанализировать выходные данные, как вы предложили, но я все еще ищу правильное решение.

Ответ №4:

Остается Win32::Process. Если код выхода из этого равен нулю, код выхода равен нулю.