我是Perl的初学者.我有一个Windows批处理脚本,其中包含多个NMake命令.此批处理脚本的现有问题是即使NMake命令在执行期间失败,ERRORLEVEL也无法正确设置.
因此,在解析日志文件之前,我们永远不知道命令是否有效.我调查了它但找不到解决方案.我,然后考虑将这个批处理脚本转换为Perl脚本,假设陷阱错误会更容易,但似乎并不那么容易:)
每当我运行我的Perl脚本时,'system'命令总是返回0.我查看了许多不同的链接,并意识到捕获'system'命令的正确返回状态并不是那么简单.不过,我尝试了这些建议,但事情并没有奏效.:(
让我提一下,被调用的NMake命令反过来在执行期间调用许多不同的命令.例如,下面提到的命令输出,即抛出"致命错误",实际上是Perl脚本(check_dir.pl)的一部分.对Perl脚本的调用是在NMake文件中编写的.
如果我直接调用这个Perl文件(check_dir.pl)并检查退出值,我得到正确的结果,即命令失败并输出非零退出值(... 意外返回退出值2).
试过Perl的系统功能,但它没有帮助.我使用了以下代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
..... ..... Unable to open dir: R:\TSM_Latest Compressing...NMAKE : fatal error U1077: 'if' : return code '0x2' Stop. child exited with value 0
还尝试过:
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";
}
Run Code Online (Sandbox Code Playgroud)
最后尝试了以下模块:
use IPC::Run qw( run timeout );
run "nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1" or die "NMake returned $?";
Run Code Online (Sandbox Code Playgroud)
似乎没有什么工作:(
如果我正在解释system错误的返回值,请纠正我.
你有:
use IPC::System::Simple qw(system);
my $exit_status = system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");
Run Code Online (Sandbox Code Playgroud)
鉴于您似乎并不关心实际输出,您可以尝试
my $exit_status = systemx(nmake =>
qw(/f _nt.mak pack_cd),
"SUB_PLAT=$PLAT",
"DR=$plat",
);
Run Code Online (Sandbox Code Playgroud)
确保你绕过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";
Run Code Online (Sandbox Code Playgroud)
生产:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
生产:
NMAKE : fatal error U1052: file 'bogus' not found Stop. child exited with value 2
事实上,即使我使用
my $status = system "nmake /f bogus";
Run Code Online (Sandbox Code Playgroud)
我得到了相同的正确和预期的输出.
我用的时候也一样
my $status = system "nmake /f bogus 2>&1";
Run Code Online (Sandbox Code Playgroud)
这些观察引出了以下问题:
您使用的是哪个版本的nmake?
该/I选项有效吗?即使您没有从命令行设置它,请注意以下事项:
/I忽略所有命令的退出代码.要设置或清除/I部分makefile,请使用!CMDSWITCHES.要忽略部分makefile的退出代码,请使用dash(–)命令修饰符或.IGNORE./K如果指定了两者,则覆盖.
所以,我把以下文件放在一起:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
这给了我输出:
perl bogus.pl NMAKE : fatal error U1077: 'c:\opt\perl\bin\perl.EXE' : return code '0x1' Stop. child exited with value 2
最后一行显示nmake的退出状态已正确传播.
你还有其他一些问题.
事实上,OP后来在评论中指出:
我想要运行的实际命令是:
system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1 | C:\\tee2 $TEMP_DIR\\modules-nt_${platlogfile}");
鉴于tee参与管道,nmake退出代码丢失并不奇怪.tee成功地能够处理输出nmake,因此它返回成功,这是脚本看到的退出代码.
因此,解决方案是捕获您nmake自己的输出,使用qx(结合适当级别的错误检查)或使用capturefrom IPC::System::Simple.然后,您可以决定是否要打印输出,保存到文件,将其放入电子邮件等...