[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[其他] [讨论]对批处理中errorlevel的几点猜测

1. 有些命令执行完毕之后,CMD不会去修改errorlevel的值,比如echo命令。

更多内容请参考:
http://bbs.bathome.net/thread-7479-1-1.html

注:那个帖子的部分结论有待商榷。

2. 有些命令执行完毕之后,且仅当命令执行完毕之后(complete),CMD会去修改errorlevel的值。

2.1 命令执行完毕,而且成功(complete successfully),CMD把errorlevel的值设置为0

c:\Test>time /t
11:01 PM

c:\Test>echo %errorlevel%
0

c:\Test>dir /b a.txt
a.txt

c:\Test>echo %errorlevel%
0


2.2 命令执行完毕,但是出错(complete with error),CMD把errorlevel的值设置为非0(大部分时候是1)

c:\Test>time /t
11:02 PM

c:\Test>echo %errorlevel%
0

c:\Test>dir /b a.log
File Not Found

c:\Test>echo %errorlevel%
1


3、如果命令在执行过程中被系统发出的中断信号(不同于用户输入的Ctrl+C等组合键)中止(abort),CMD不会去修改errorlevel的值。命令中存在||时,情况有所不同。

3.1

c:\Test>time /t
11:03 PM

c:\Test>echo %errorlevel%
0

c:\Test>attrib +r a.txt

c:\Test>dir >a.txt
Access is denied.

c:\Test>echo %errorlevel%
0


注:CMD在解释执行dir >a.txt的过程中,由于重定向的优先级高,于是首先尝试写文件(获取文件a.txt的写权限)。但是因为该文件设置了只读属性,所以操作失败,系统发出中断信号中止掉整条命令。换句话说,dir命令根本没有被执行。

3.2

c:\Test>time /t
11:04 PM

c:\Test>echo %errorlevel%
0

c:\Test>attrib +r a.txt

c:\Test>dir >a.txt || echo bbs.bathome.net
Access is denied.
bbs.bathome.net

c:\Test>echo %errorlevel%
1


注:如前文所述,dir >a.txt被中止之后,CMD并未立刻去修改errorlevel的值。它要去判断是否触发||。关于||,微软是这样说的:

Cmd.exe runs the first command, and then runs the second command only if the first command did not complete successfully.


很显然,||左边的命令没有成功地执行完毕,满足触发||的条件,CMD把errorlevel的值修改为1,然后||认为自己接受到一个非0的返回码,继续执行后面的echo命令。

3.3

c:\Test>time /t
11:05 PM

c:\Test>echo %errorlevel%
0

c:\Test>attrib +r a.txt

c:\Test>dir >a.txt && echo bbs.bathome.net
Access is denied.

c:\Test>echo %errorlevel%
0


注:dir >a.txt被中止之后,不满足触发&&的条件,CMD不去修改errorlevel的值,整行命令直接结束。

【扩展阅读】
https://stackoverflow.com/questions/34987885/what-are-the-errorlevel-values-set-by-internal-cmd-exe-commands/34987886#34987886
1

评分人数

    • CrLf: 看来你是对的...感谢分享技术 + 1

回复 6# ivor


    单就 xx || echo %errorlevel% 这一句来说吧,%errorlevel% 是在 cmd 对整行进行预处理时就解释了的,而不是在 echo %errorlevel% 这句预处理时解释的,所以你看到的 errorlevel 是执行 xx 之前的:
  1. xx || echo %errorlevel%
  2. xx || echo %errorlevel%
  3. ::同样的两句,显示的 errorlevel 却不同,原因就在于这里的 errorlevel 都是隔夜饭,不是新鲜出炉的
复制代码
可以改用变量延迟来解释变量:
  1. xx || cmd /v /c echo !errorlevel!
  2. ::%errorlevel% 与 !errorlevel! 的区别在于,前者是以行(更确切地说应该是复合语句)为单位解释的,取到的是上一行运行结束后的变量,而后者是以一条命令为单位临时解释的,所以取到的是上一条命令的结果
复制代码

TOP

回复 5# qzwqzw




    不赞同!!!!   errorlevel的值是在整条语句执行完成之后才改变的,下面是我测试的结果
  1. C:\Users\Administrator>xx
  2. 'xx' 不是内部或外部命令,也不是可运行的程序
  3. 或批处理文件。
  4. C:\Users\Administrator>xx || echo %errorlevel%
  5. 'xx' 不是内部或外部命令,也不是可运行的程序
  6. 或批处理文件。
  7. 9009
  8. C:\Users\Administrator>echo %errorlevel%
  9. 1
  10. C:\Users\Administrator>xx
  11. 'xx' 不是内部或外部命令,也不是可运行的程序
  12. 或批处理文件。
  13. C:\Users\Administrator>echo %errorlevel%
  14. 9009
  15. C:\Users\Administrator>xx || echo %errorlevel%
  16. 'xx' 不是内部或外部命令,也不是可运行的程序
  17. 或批处理文件。
  18. 9009
  19. C:\Users\Administrator>echo %errorlevel%
  20. 1
复制代码

TOP

通过以下测试可以确认
||并不是根据errorlevel来判断是否执行右侧的语句

Microsoft Windows [版本 5.2.3790]
(C) 版权所有 1985-2003 Microsoft Corp.

C:\Documents and Settings\Administrator>xx
'xx' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

C:\Documents and Settings\Administrator>echo %errorlevel%
9009

C:\Documents and Settings\Administrator>echo not set errorlevel
not set errorlevel

C:\Documents and Settings\Administrator>echo %errorlevel%
9009

C:\Documents and Settings\Administrator>echo not set errorlevel || echo not run
not set errorlevel

C:\Documents and Settings\Administrator>xx || echo run
'xx' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
run

C:\Documents and Settings\Administrator>


根据以下测试可以证明
||会在左侧代码未成功完成时置errorlevel为1

C:\Documents and Settings\Administrator>xx
'xx' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

C:\Documents and Settings\Administrator>echo %errorlevel%
9009

C:\Documents and Settings\Administrator>echo not set errorlevel || echo not run
not set errorlevel

C:\Documents and Settings\Administrator>echo %errorlevel%
9009

C:\Documents and Settings\Administrator>xx || echo run
'xx' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
run

C:\Documents and Settings\Administrator>echo %errorlevel%
1


根据以下测试可以证明
||是在右侧命令执行之前置errorlevel,而非整条语句执行完成后

C:\Documents and Settings\Administrator>xx
'xx' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

C:\Documents and Settings\Administrator>echo %errorlevel%
9009

C:\Documents and Settings\Administrator>xx || if errorlevel 1 if not errorlevel 2 echo errorlevel == 1
'xx' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
errorlevel == 1


综合以上论断
可以确认在||在左侧语句未成功完成时
会置errorlevel为1
同时启动执行右侧的语句
2

评分人数

    • plp626: 喜欢这样的论证;有理有据;PB + 10 技术 + 1
    • CrLf: 这个证明很有力技术 + 1
天的白色影子

TOP

噢,俺英语不好~
不过那个疑惑仍然没解开,||的触发条件究竟是什么?莫非是多条相互独立的触发条件(原来一直以为只有 errorlevel,因为从来没有遇到其他情况)?
另外,从楼主的猜测还得出一个有趣的推论,就是 errorlevel 并不是在一条命令结束之后立刻被定义的,而是执行完命令并判断连接符是否为 || 才决定何时定义(&、&&、|均不影响,唯独 || 例外)...

TOP

回复 2# CrLf


not complete successfully和“命令运行失败”不是一回事

TOP

本帖最后由 CrLf 于 2011-10-8 13:29 编辑

但是如此一来,||的触发条件似乎更难理解了,何谓“前一条命令运行失败”呢?依照楼主所做的猜测,||可以不通过 errorlevel 就能够判断命令是否成功运行,这是楼主观点的基础,可是如何证明?本贴中似乎没有提供针对此问题直接证据或者客观推导,唯一的论据只是微软含糊不清的一面之辞...
再进一步,若果真如此,那么它又是以什么为“命令执行失败”的依据呢?

TOP

返回列表