命令脚本退出代码看不到同一行&&或||?

Har*_*nch 4 windows cmd batch-file

考虑一个名为t.cmd的命令脚本,它只包含以下两行:

@exit /b 123
@echo If you see this, THEN EXIT FAILED..
Run Code Online (Sandbox Code Playgroud)

因此,脚本只是将脚本执行过程的退出代码设置为123,但不会杀死cmd.exe.最后的回声确认退出实际上导致立即返回(其输出不应出现).

现在执行此脚本,然后打印出%errorlevel%:

>t.cmd

>echo %errorlevel%
123
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都那么好:一切都表现得与预期一致.

但现在在一行上执行上述所有操作,使用&&进行条件执行:

>t.cmd && echo %errorlevel%
123
Run Code Online (Sandbox Code Playgroud)

我不指望这样:如果t.cmd确实返回非0退出代码,那么它应该在执行之后停止&&(即echo)之后的所有内容.我们看到它打印的事实意味着它DID执行.到底他妈发生了什么?

如果在一行上执行上述所有操作,请使用|| 用于条件执行:

>t.cmd || echo %errorlevel%

>
Run Code Online (Sandbox Code Playgroud)

这种行为也与我的预期相反(尽管它与上面的&&行为一致).

请注意,这种奇怪的行为仅适用于bat文件,但不适用于"原始命令".

证明:考虑以下命令行交互,而不是调用t.cmd,我尝试执行bogus命令abcdef:

>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
Run Code Online (Sandbox Code Playgroud)

这里,&&和|| 立即看到失败的bogus命令的退出代码.

那么为什么cmd文件的行为有所不同呢?

在Windows中的文件重定向中观察到cmd.exe中可能存在的相关错误,并且%errorlevel%

另外,我知道ERRORLEVEL不是%ERRORLEVEL%

顺便说一句,上面的代码都是在Win 7 Pro 64位框上执行的.我不知道其他版本的Windows如何表现.

Jos*_*efZ 5

随着t.bat略作如下修改:

@exit /b 123%~1
@echo If you see this, THEN EXIT FAILED..
Run Code Online (Sandbox Code Playgroud)

想出下一个输出:

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

==>
Run Code Online (Sandbox Code Playgroud)

资源

编辑启发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

==>
Run Code Online (Sandbox Code Playgroud)

编辑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!
Run Code Online (Sandbox Code Playgroud)

输出(来自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

==>
Run Code Online (Sandbox Code Playgroud)

注意

  • ||显示错误级别1虽然'abcd' not recognized误差应9009同时
  • ||保持errorlevel 2不变的FIND: Invalid switch错误.
  • ||分支评估的call t.cmd 333同时,
  • &&分支评估t.cmd 222.

(call )看到DBenham的答案:

如果你想强制使用errorlevelto 0,那么你可以使用这种完全不直观但非常有效的语法:(call ).之后的空间call至关重要.

如果要设置errorlevel1,则可以使用(call).至关重要的是,之后没有任何空间call.