首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >命令脚本退出代码没有被一行所看到&或者??

命令脚本退出代码没有被一行所看到&或者??
EN

Stack Overflow用户
提问于 2015-07-02 00:26:14
回答 3查看 2.3K关注 0票数 5

考虑一个名为t.cmd的命令脚本,它仅由以下两行组成:

代码语言:javascript
运行
复制
@exit /b 123
@echo If you see this, THEN EXIT FAILED..

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

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

代码语言:javascript
运行
复制
>t.cmd

>echo %errorlevel%
123

到目前为止一切都很好:一切都和预期的一样。

但是现在在一行上执行上面的所有内容,使用&& for条件执行:

代码语言:javascript
运行
复制
>t.cmd && echo %errorlevel%
123

我并不期望这样的情况:如果t.cmd真的返回了一个非0的退出代码,那么它应该在那之后停止所有&& (即回显)的执行。我们看到它打印的事实意味着它确实执行了。到底是怎么回事?

如果在一行上执行上面的所有内容,则在有条件的执行过程中使用\来执行条件:

代码语言:javascript
运行
复制
>t.cmd || echo %errorlevel%

>

这种行为也与我所期望的相反(而且它与上面的&&行为是一致的)。

请注意,这种奇怪的行为只适用于bat文件,而不适用于“原始命令”。

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

代码语言:javascript
运行
复制
>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是如何运行的。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-07-02 03:57:38

t.bat略有修改,如下所示:

代码语言:javascript
运行
复制
@exit /b 123%~1
@echo If you see this, THEN EXIT FAILED..

考虑下一个输出:

代码语言:javascript
运行
复制
==>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

==>

资源

编辑来启发EnableDelayedExpansion

代码语言:javascript
运行
复制
==>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

代码语言:javascript
运行
复制
@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):

代码语言:javascript
运行
复制
==>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 )上,参见德本纳姆的回答

如果您想强制errorlevel0,那么您可以使用这个完全非直观但非常有效的语法:(call )call之后的空间非常重要。 如果要将errorlevel设置为1,可以使用(call)。在call之后没有任何空间是至关重要的。

票数 5
EN

Stack Overflow用户

发布于 2015-07-02 02:02:26

读取行时展开%错误级别%。因此,在读取行时是123,因此来自前面的命令,而不是t.exe。&&只在当前错误级别(来自t命令)为0时执行。

有关更多信息,请参见setlocal /?set /?

票数 4
EN

Stack Overflow用户

发布于 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的要求进行操作:

代码语言:javascript
运行
复制
@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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31173772

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档