考虑一个名为t.cmd的命令脚本,它仅由以下两行组成:
@exit /b 123
@echo If you see this, THEN EXIT FAILED..
因此,脚本只是将脚本的执行过程的退出代码设置为123,但不会杀死cmd.exe。最后一个回显确认退出实际上会立即返回(它的输出不应该出现)。
现在执行这个脚本,然后打印出%errorlevel%:
>t.cmd
>echo %errorlevel%
123
到目前为止一切都很好:一切都和预期的一样。
但是现在在一行上执行上面的所有内容,使用&& for条件执行:
>t.cmd && echo %errorlevel%
123
我并不期望这样的情况:如果t.cmd真的返回了一个非0的退出代码,那么它应该在那之后停止所有&& (即回显)的执行。我们看到它打印的事实意味着它确实执行了。到底是怎么回事?
如果在一行上执行上面的所有内容,则在有条件的执行过程中使用\来执行条件:
>t.cmd || echo %errorlevel%
>
这种行为也与我所期望的相反(而且它与上面的&&行为是一致的)。
请注意,这种奇怪的行为只适用于bat文件,而不适用于“原始命令”。
证明:考虑下面的命令行交互,我尝试执行冒充命令abcdef,而不是调用t.cmd:
>abcdef
'abcdef' is not recognized as an internal or external command,
operable program or batch file.
>echo %errorlevel%
9009
>abcdef && echo %errorlevel%
'abcdef' is not recognized as an internal or external command,
operable program or batch file.
>abcdef || echo %errorlevel%
'abcdef' is not recognized as an internal or external command,
operable program or batch file.
9009
在这里,&和\都会立即看到失败的伪命令的退出代码。
,那么为什么cmd文件的行为不同呢?
在cmd.exe中观察到了一个可能相关的Windows中的文件重定向和%错误级别%错误。
另外,我知道ERRORLEVEL不是%ERRORLEVEL
顺便说一下,上面的代码都是在Win 7 Pro 64位框上执行的。我不知道其他版本的Windows是如何运行的。
发布于 2015-07-02 03:57:38
t.bat
略有修改,如下所示:
@exit /b 123%~1
@echo If you see this, THEN EXIT FAILED..
考虑下一个输出:
==>t.bat 1
==>echo %errorlevel%
1231
==>t.bat 2&echo %errorlevel%
1231
==>echo %errorlevel%
1232
==>cmd /V /C t.bat 3^&echo !errorlevel!
1233
==>echo %errorlevel%
0
==>cmd /V /C t.bat 4^&echo !errorlevel!^&exit /B !errorlevel!
1234
==>echo %errorlevel%
1234
==>
资源
%~1
等特别网页) 命令行参数(参数)编辑来启发EnableDelayedExpansion
==>cmd /v
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.
==>t.bat 5&echo !errorlevel!
1235
==>echo %errorlevel%
1235
==>
编辑2来启发(或混淆?) &&
和||
。将下一个代码段保存为errlevels.cmd
@ECHO ON >NUL
@SETLOCAL enableextensions enabledelayedexpansion
(call )
@echo ^(call ^) command clears errorlevel %errorlevel%
abcd /G>NUL 2>&1
@echo abcd /G: "'abcd' not recognized" errorlevel %errorlevel%
abcd /G>NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
@echo abcd /G: ^|^| changed errorlevel %errorlevel%
find /G >NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
@echo find /G: ^|^| unchanged errorlevel %errorlevel%
call t.cmd 333 && echo YES !errorlevel! || echo NO !errorlevel!
type t.cmd
t.cmd 222 && echo YES !errorlevel! || echo NO !errorlevel!
Output (来自errlevels.cmd
):
==>errlevels.cmd
==>(call )
(call ) command clears errorlevel 0
==>abcd /G 1>NUL 2>&1
abcd /G: "'abcd' not recognized" errorlevel 9009
==>abcd /G 1>NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
NO 1
abcd /G: || changed errorlevel 1
==>find /G 1>NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
NO 2
find /G: || unchanged errorlevel 2
==>call t.cmd 333 && echo YES !errorlevel! || echo NO !errorlevel!
NO 333
==>type t.cmd
@exit /B %~1
==>t.cmd 222 && echo YES !errorlevel! || echo NO !errorlevel!
YES 222
==>
请注意,
||
显示错误级别1,尽管'abcd' not recognized
错误应该是9009
,而||
保持错误级别2不变,以防止FIND: Invalid switch
错误。||
分支在call t.cmd 333
中进行评估&&
分支在t.cmd 222
中进行评估。在(call )
上,参见德本纳姆的回答:
如果您想强制
errorlevel
到0
,那么您可以使用这个完全非直观但非常有效的语法:(call )
。call
之后的空间非常重要。 如果要将errorlevel
设置为1
,可以使用(call)
。在call
之后没有任何空间是至关重要的。
发布于 2015-07-02 02:02:26
读取行时展开%错误级别%。因此,在读取行时是123,因此来自前面的命令,而不是t.exe。&&只在当前错误级别(来自t命令)为0时执行。
有关更多信息,请参见setlocal /?
和set /?
。
发布于 2016-02-21 23:50:03
@JosefZ的答复很好地覆盖了ERRORLEVEL
和退出代码在命令脚本方面的差异。
不幸的是,正如他指出的那样,&&
和||
运算符只有在使用call
命令调用命令脚本时才能工作。在大多数情况下,您更希望用户只运行命令脚本,而不必记住每次使用call
作为前缀。
通常,我希望脚本同时设置ERRORLEVEL
和退出代码,以指示失败(以便使我的脚本行为与常规可执行文件相同)。我过去经常使用exit /b <nonzero>
来尝试这样做,但是遇到了上面提到的问题。
结果是,Windows命令解释器使用执行的最后一个命令的退出代码退出。具有讽刺意味的是,exit /b <nonzero>
命令的实际退出代码是0(因为它成功退出)。它确实设置了ERRORLEVEL
,但没有设置退出代码。因此,该命令将无法工作。所有这些的解决方案是:(1)使用cmd /c exit <nonzero>
命令,(2)让它作为脚本中的最后一个命令执行。由于cmd
命令返回到脚本,然后执行下一个命令,因此使其成为执行的最后一行的唯一方法是让它成为脚本的最后一行。
因此,这里有一个解决方案,使所有事情都能按照OP的要求进行操作:
@echo off & setlocal
if "%1" equ "fail" (
echo -- Failure
goto fail
) else (
echo -- Success
exit /b 0
)
:fail
@REM // Exit with script a failure exit code.
cmd /c exit 37
https://stackoverflow.com/questions/31173772
复制相似问题