当我使用&&和cmd时,为什么cmd运行我的第二个命令?即使第一个失败了?

时间:2014-07-05 07:12:56

标签: windows cmd

我正在尝试Rust。我想编译一个程序,只有成功,才能运行它。我正在努力:

rustc hello.rs && hello

但即使编译失败,hello.exe也会一直运行。

如果我尝试

rustc hello.rs
echo Exit Code is %errorlevel% 

我得到"退出代码是101"。

根据我的理解,唯一的真实价值是0厘米,其中101显然不是,&&懒惰评估,为什么它运行hello


rustc.bat看起来像这样:

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

2 个答案:

答案 0 :(得分:9)

非常好奇。把CALL放在前面,一切都应该没问题。

call rustc hello.rs && hello

我不完全理解这种机制。我知道&&||不会直接读取动态%errorlevel%值,而是会在较低级别运行。无论当前%errorlevel%值如何,它们都会根据最近执行的命令的结果有条件地触发。 ||甚至可以针对未设置%errorlevel%的故障触发!有关示例,请参阅File redirection in Windows and %errorlevel%batch: Exit code for "rd" is 0 on error as well

您的rustc是批处理文件,行为会根据是否使用CALL而更改。如果没有CALL,&&||运算符只会响应命令是否运行 - 它们会忽略脚本的退出代码。使用CALL,它们可以正确响应脚本的退出代码,以及响应脚本是否运行失败(可能脚本不存在)。

换句话说,如果通过CALL启动退出代码,批处理脚本只会通知&&||运营商。

<强>更新

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

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

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

真正的杀手是EXIT /B 1 向另一个&&||报告ERRORLEVEL,除非通过呼叫。条件运算符检测到EXIT命令成功执行,并忽略返回的ERRORLEVEL!

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

,则可以实现预期的行为
cmd /c exit %errorlevel%

无论脚本是否由CALL调用,这都会正确地将返回的ERRORLEVEL报告给&&||

以下是一些演示我的意思的测试脚本。

<强> 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

>

答案 1 :(得分: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

按预期工作......