为什么cmd在使用&时运行我的第二个命令,尽pipe第一个命令失败了?

我正在试用Rust。 我想编译一个程序,只有成功,运行它。 所以我试着:

rustc hello.rs && hello 

但hello.exe总是运行,即使编译失败。

如果我尝试

 rustc hello.rs echo Exit Code is %errorlevel% 

我得到“退出代码是101”。

据我了解,唯一的truthy值是0 cmd,其中101显然不是,&&是懒惰评估,所以为什么它跑了hello


rustc.bat看起来像这样:

 @echo off SET DIR=%~dp0% cmd /c "%DIR%..\lib\rust.0.11.20140519\bin\rustc.exe %*" exit /b %ERRORLEVEL% 

非常好奇这个。 把一个CALL放在前面,一切都会好的。

 call rustc hello.rs && hello 

我不完全理解这个机制。 我知道&&|| 不要直接读取动态%errorlevel%值,而是在较低的级别上运行。 它们根据最近执行的命令的结果有条件地启动,而不管当前的%errorlevel%值。 || 甚至可能因未能设置%errorlevel%失败! 请参阅Windows中的文件重定向和%errorlevel%和批处理:错误中的“rd”的退出代码也是例子。

您的rustc是一个批处理文件,并且行为根据是否使用CALL而改变。 没有CALL, &&|| 操作员只响应命令是否运行 – 他们忽略脚本的退出代码。 通过CALL,他们可以正确响应脚本的退出代码,除了响应脚本运行失败(也许脚本不存在)之外。

换句话说,批处理脚本只能通知&&|| 有关退出代码的操作员是否通过CALL启动。

UPDATE

阅读foxidrive的(现在删除)答案更仔细,我意识到情况更复杂。

如果使用CALL,则一切按预期工作 – &&|| 响应脚本返回的ERRORLEVEL。 在脚本中,ERRORLEVEL可以设置为1,只要没有后续脚本命令清除错误,返回的ERRORLEVEL为1就会正确地报告给&&||

如果不使用CALL,那么&&|| 响应脚本中最后执行的命令的错误代码。 脚本中的早期命令可能会将ERRORLEVEL设置为1.但是,如果最后一个命令是正确执行的ECHO语句,那么&&|| 响应ECHO命令的成功,而不是脚本返回的ERRORLEVEL 1。

真正的杀手是EXIT /B 1不会将ERRORLEVEL报告给&&|| 除非脚本通过CALL调用。 条件运算符检测到EXIT命令执行成功,忽略返回的ERRORLEVEL!

如果脚本执行的最后一个命令是预期行为:

 cmd /c exit %errorlevel% 

这将正确地将返回的ERRORLEVEL报告给&&|| ,不管该脚本是否被CALL调用。

这里有一些测试脚本来说明我的意思。

test1.bat

 @echo off :: This gives the correct result regardless if CALL is used or not :: First clear the ERRORLEVEL (call ) :: Now set ERRORLEVEL to 1 (call) 

test2.bat

 @echo off :: This only gives the correct result if CALL is used :: First clear the ERRORLEVEL (call ) :: Now set ERRORLEVEL to 1 (call) rem This command interferes with && or || seeing the returned errorlevel if no CALL 

test3.bat

 @echo off :: This only gives the correct result if CALL is used :: First clear the ERRORLEVEL (call ) :: Now set ERRORLEVEL to 1 (call) rem Ending with EXIT /B does not help exit /b %errorlevel% 

test4.bat

 @echo off :: This gives the correct result regardless if CALL is used or not :: First clear the ERRORLEVEL (call ) :: Now set ERRORLEVEL to 1 (call) rem The command below solves the problem if it is the last command in script cmd /c exit %errorlevel% 

现在使用和不使用CALL进行测试:

 >cmd /v:on Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. >test1&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Failure with errorlevel=1 >test2&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Success, yet errorlevel=1 >test3&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Success, yet errorlevel=1 >test4&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Failure with errorlevel=1 >call test1&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Failure with errorlevel=1 >call test2&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Failure with errorlevel=1 >call test3&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Failure with errorlevel=1 >call test4&&echo Success, yet errorlevel=!errorlevel!||echo Failure with errorlevel=!errorlevel! Failure with errorlevel=1 > 

快速演示来证明这一点:

 @ECHO OFF SETLOCAL CALL q24983584s 0&&ECHO "part one" ECHO done one CALL q24983584s 101&&ECHO "part two" ECHO done two GOTO :EOF 

q24983584s.bat在哪里

 @ECHO OFF SETLOCAL EXIT /b %1 GOTO :EOF 

按预期工作…