请注意:
c:\temp\1.cmd
@echo off
setlocal
cmd /c dir aaa
IF %ERRORLEVEL% NEQ 0 GOTO fail
GOTO end
:fail
echo - Script failed
:end
endlocal
现在,如果我在命令提示符下运行它:
C:\temp> cmd
Microsoft Windows [Version 10.0.16299.967]
(c) 2017 Microsoft Corporation. All rights reserved.
C:\temp>c:\temp\1.cmd
Volume in drive C has no label.
Volume Serial Number is 4A5E-F223
Directory of C:\temp
File Not Found
- Script failed
C:\temp>echo %errorlevel%
1
C:\temp>
现在我从 Powershell 运行它:
C:\temp> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.16299.967
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.16299.967
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
C:\temp> cmd /c C:\temp\1.cmd
Volume in drive C has no label.
Volume Serial Number is 4A5E-F223
Directory of C:\temp
File Not Found
- Script failed
C:\temp> $LASTEXITCODE
0
C:\temp>
据我所知,退出代码应该正确传播。那么,问题出在哪里呢?
Note: This answer was substantially rewritten after new information came to light.
来补充jazzdelightsme 的有效解决方案 https://stackoverflow.com/a/55289640/45375和一些一般指导和背景信息:
-
When calling a batch file from outside cmd.exe
, such as from PowerShell, invoke it as cmd /c 'file.cmd ... & exit'
or - if string interpolation is needed - as
cmd /c "file.cmd ... & exit"
, which then requires escaping embedded "
as `"
[1]. This ensures that it behaves as it would when called from inside cmd.exe
with respect to its exit code (error level), i.e. ensures that the batch file's exit code reliably becomes cmd.exe
's process exit code.
-
这个帖子 https://stackoverflow.com/q/66975883/45375详细解释了这个问题和这个晦涩难懂的解决方法。
-
Note: The simpler workaround based on
call
- cmd /c call file.cmd ...
- works in principle, but has an unwanted side effect when (of necessity double-quoted[2]) arguments with ^
characters are passed: Due to use of call
, ^
characters ("carets", strictly speaking circumflex accents, U+005E http://www.fileformat.info/info/unicode/char/5e) are invariably doubled, so that say, argument "a ^ 2"
, is seen by the batch file as "a ^^ 2"
; it is unclear what the purpose of this behavior is, but it has seemingly always existed - see this answer https://stackoverflow.com/a/66250528/45375 for details on cmd.exe
's parser.
-
Without the & exit
解决方法,只有确保以下情况,您才会获得所需的行为all代码路径以下列方式之一退出 - 缺少代码路径是一个很容易犯的错误:
-
exit
with no参数,它正确地中继最近执行的命令的退出代码。
-
Caveat:
exit
without /b
立即退出cmd.exe
实例作为一个整体,因此它不适合在可以交互运行或必须可从其调用的批处理文件中使用other批处理文件并将控制权返回给这些批处理文件。
-
exit /b <code>
or exit <code>
, where <code>
表示所需的退出代码,即指定一个explicit退出代码,如 jazzdelightsme 的解决方案中所示。
-
Caveat:退出批处理文件
exit /b
没有明确的<code>
争论 does not传递最近执行的命令的退出代码,而不带cmd /c <batch-file> ... `& exit
解决方法 - 请参阅这个答案 https://stackoverflow.com/a/66250528/45375.
附加背景信息,在上下文中你的代码:
奇怪的是,与outside调用批处理文件without & exit
(or call
),诸如此类的陈述if
, goto
, echo
, and endlocal
, 乃至REM
(但是,奇怪的是,不是::
) 重置退出代码cmd.exe
稍后报告给0
- 虽然inside that cmd.exe
会议%ERRORLEVEL%
按通常的方式设置,这意味着此类语句对当前没有影响%ERRORLEVEL%
value.
所以:
-
当您的批处理文件运行时inside cmd.exe
,设置命令后面的具体语句%ERRORLEVEL%
to 1
(cmd /c dir aaa
),即if
, goto
, echo
and endlocal
声明,preserve这个值,以及%ERRORLEVEL%
最终获得价值1
退出批处理文件后。
- 奇怪的是,错误级别仅设置after涉及批处理文件调用的语句,因此类似
file.cmd || exit
does not工作,因为||
操作员无法识别file.cmd
调用失败。这就是解决方法使用的原因&
而不是||
.
-
当您的批处理文件运行时outside cmd.exe
, and isn't调用与cmd /c "<batch-file> ... & exit"
(or cmd /c call <batch-file> ...
), 后面的语句相同%ERRORLEVEL%
-setting 命令突然重置退出代码cmd.exe
其本身随后向0
,而不是保留批处理文件执行后%ERRORLEVEL%
value.
[1] Situationally, you can get away with cmd /c <batch-file> ... `& exit
, i.e. without enclosing the arguments to /c
in a single, overall string, but that breaks if the batch-file path needs double-quoting and at least one double-quoted pass-through argument is also present.
[2] ^
chars. in unquoted arguments, as usual, are interpreted as cmd.exe
's escape character and therefore removed.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)