标题: [转贴] 批处理内部命令对错误返回码errorlevel的影响 [打印本页]
作者: qzwqzw 时间: 2010-4-2 15:11 标题: 批处理内部命令对错误返回码errorlevel的影响
转自:http://tieba.baidu.com/f?kz=579067365
原因:所在地无法上帖吧,在这里留个备份
提示:本文内容仅原文转载,未做任何测试!
注:本文不考虑chdir,erase,mkdir,rename,rmdir,因为它们与cd,del,md,ren,rd同义,因此有37个内部命令,内部命令加 /? 不改变 errorlevel
管道符与重定向,如 |,&,||,&&,>,>>,1>,2> 等不改变 errorlevel
以下20个命令如果执行成功,不改变 errorlevel
assoc break call cls echo
endlocal for ftype goto if
path pause popd prompt rd
rem set shift start title
call 是否改变 errorlevel 由调用的内容决定
color 在 Windows 2000 中不改变 errorlevel
exit /b 不加退出码不改变 errorlevel
for 命令 in 后的括号内如果是命令,则这个命令不改变errorlevel
rd 命令在文件夹非空或不存在时,也不改变 errorlevel
set 删除变量,返回1, set 可以直接修改 errorlevel ,这样会使 errorlevel 成为一般变量,以后不能用来记录命令返回值,但可用 IF [NOT] ERRORLEVEL number command 语句判断 errorlevel
start 命令如果加 /w 或 /wait 选项,可以改变 errorlevel
以上结果仅凭个人测试
作者: wc726842270 时间: 2011-3-4 15:38
以上的我也没有测试,(仅对SET试了一下),LZ保存的扩展名应该是BAT,不知扩展名为CMD时能否逃过这些
作者: CrLf 时间: 2011-7-9 21:38
今天碰到头疼的事了...请问 tree 是否不存在大于 0 的返回值呢?如果有,又是什么时候?另外,如何通过最简洁高效的命令来判断一个文件是否不存在子文件夹呢?我原本打算在代码中用类似下面的思路:- tree "%cd%" >nul 2>nul||echo 不存在子文件夹
复制代码
但是调试了几遍总是不对,最后发现 tree 好像碰到无子目录的情况也不会返回大于 0 的 errorlevel
作者: powerbat 时间: 2011-7-9 22:10
猜测是tree函数(假设tree命令对应tree函数)不会返回非零值。微软的程序有的也很矬。
关键是看不到cmd源码啊。
作者: CrLf 时间: 2011-7-9 22:32
4# powerbat
Thanks,看来貌似真的没有指望了?唉,微软真不给力啊
作者: Hello123World 时间: 2011-7-10 14:01
echo命令由于简单,怎么使他失败呢?——所以echo不改变errorlevel的返回值(只成功不失败,自然返回值也就一个),那20个都是这个原因吗?- 以下20个命令如果执行成功,不改变 errorlevel
- assoc break call cls echo
- endlocal for ftype goto if
- path pause popd prompt rd
- rem set shift start title
复制代码
作者: qzwqzw 时间: 2011-7-11 10:05
6# Hello123World
首先有些命令会有失败的情况
比如set
其次执行成功不设置errorlevel
不等同执行成功设置errorlevel为0
比如执行前errorlevel为3
在执行echo成功后errorlevel为3
而不是0
作者: CrLf 时间: 2011-7-15 13:04
7# qzwqzw
这是否说明部分内部命令不存在返回值呢?比如 echo 和 if、for
作者: CrLf 时间: 2014-5-12 22:11
楼主看这里:
|| 会改变退出码的实例
话说以前好像也碰到过 || 改变退出码的情况,不知道是不是记错了
作者: qzwqzw 时间: 2014-11-24 22:41
本帖最后由 qzwqzw 于 2014-12-1 22:49 编辑
很早的请求
最近终于有了些分析结果
最终结论
||确实与& && 不同
如果其左侧语句执行返回非0的值
||会将这个返回值写入errorlevel
9楼链接中的语句
(for /f %%a in ('dir /ad /b test') do break)
在当前目录不存在test时
它的返回值为1(实际是cmd /c dir /ad /b test的返回值)
只是for语句单独执行时这个返回值并不写入errorlevel
而当与||联用时
||会将其返回值写入errorlevel
顺便解答一下7楼的问题
这里出现了一点认识上的混淆
几乎所有命令都会有返回值
但是并非所有返回值都会写入errorlevel
比如echo命令执行后会返回零值
但这个零值并不写入errorlevel(推测是为了向下兼容DOS)
而&& || 是依据返回值作为判断条件的
这也是为什么echo没有写errorlevel
却仍然可以放在&&与||的左侧参与逻辑运算
另外的测试分析发现
errorlevel也不全是函数的返回值
比如执行不存在的命令时errorlevel是9009
但这条语句的返回值实际上是1
因此下面语句的输出结果是1而非9009
$xxx || echo !errorlevel!
而如果使用使用以下命令则可以看出||也可以写入非1的errorlevel
replace $xxx $yyy || echo !errorlevel!
参考链接:
[讨论]对批处理中errorlevel的几点猜测
http://www.bathome.net/redirect. ... 18&fromuid=3023
作者: CrLf 时间: 2014-11-24 23:47
本帖最后由 CrLf 于 2014-11-25 02:59 编辑
回复 10# qzwqzw
挑个刺:
它的返回值为1(实际是cmd /c dir /ad /b test的返回值)
cmd /c dir /ad /b test 返回值为 0
真正改变内部“返回值”的是无取值的 for /f,再由 || 把它表现到 errorlevel 变量中:- (for /f %%a in ("") do echo 这里不可能显示)||echo !errorlevel!
复制代码
作者: qzwqzw 时间: 2014-11-25 00:30
本帖最后由 qzwqzw 于 2014-11-25 11:34 编辑
不好意思
编辑过程中
误操作点了删除
导致回复帖也无法显示了
我这里测试cmd /c dir /ad /b test会将errorlevel置1
不知道你是如何测试的
以下语句for /f有取值(此处有误)errorlevel也会被置1- (for /f %%f in ('$xxx') do echo+%%f)||echo+!errorlevel!
复制代码
这说明for的返回值设置是很复杂的
要论证到底是何缘由需要更仔细的分析测试
作者: CrLf 时间: 2014-11-25 00:47
本帖最后由 CrLf 于 2014-11-25 04:03 编辑
回复 12# qzwqzw
其实是我看你的回复不见了之后自己删的,然后默默地修改了原帖...
dir 的返回值确实可能非 0,这我混乱了,但 11 楼的刺仍然部分成立
12 楼的 $xxx 输出是在 StdOut,不在 StdIn,所以 for /f 的输入仍然为空
致命一击:- (for /f %%f in ('$xxx 2^>^&1') do echo+%%f)||echo+!errorlevel!
复制代码
- (for /f %f in ('"dir 一个不存在的文件 2>&1 >nul"') do echo+%f)||echo+[!errorlevel!]
复制代码
所以我认为 for /f 的返回值与其中命令的返回值无关,而仅与 for /f 有无输入以及 for 本身的参数错误有关,详见下方测试结果
-------------------------------------------------------------------------------------
无输入时等于 1:- (for /f %%f in (' ') do break)||echo+!errorlevel!
复制代码
- (for /f %%f in ("") do break)||echo+!errorlevel!
复制代码
- (for /f "skip=99999999" %%f in (a.txt) do break)||echo+!errorlevel!
复制代码
参数错误也等于 1:- (for /f "错误的参数" %%f in ("test") do break)||echo+!errorlevel!
复制代码
也有等于 2 的时候:- (for /f %%f in (一个不存在的文件) do break)||echo+!errorlevel!
复制代码
有趣的是,好像有且仅有一种情况是等于 3 的:- (for /f %%f in (^") do break)||echo+!errorlevel!
复制代码
作者: qzwqzw 时间: 2014-11-25 11:08
本帖最后由 qzwqzw 于 2014-11-25 11:29 编辑
回复 13# CrLf
真正改变内部“返回值”的是无取值的 for /f,再由 || 把它表现到 errorlevel 变量中:
我现在也同意你的这个观点
昨晚我也是混乱了
看来确实不能熬夜了
还是你精力充沛啊
经过分析
for /f的返回值分为三种情况
第一种是for选项及遍历集解析错误的返回值
这个基本都是1
第二种是for的遍历集set创建时的返回值
因为这个set可以是文件名
所以主要是使用CreateFile()打开文件时返回的
常见的返回值包括
ERROR_SUCCESS
0 (0x0)
The operation completed successfully.
ERROR_INVALID_FUNCTION
1 (0x1)
Incorrect function.
ERROR_FILE_NOT_FOUND
2 (0x2)
The system cannot find the file specified.
ERROR_PATH_NOT_FOUND
3 (0x3)
The system cannot find the path specified.
所以13楼最后代码中的^"被判断成了一个无效的路径
使用C:\$xxx\$yyy可以得到同样的返回值
另外ERROR_SUCCESS是不会被for/f返回的
因为当打开文件成功后for/f仍要继续解析set遍历集及do执行语句
还有些不常见的返回值
打开C:\System Volume Information时的ERROR_ACCESS_DENIED(5)
打开C:\WINDOWS\system32\config\sam时的ERROR_SHARING_VIOLATION(32)
具体错误代码参考以下链接
http://technet.microsoft.com/zh-cn/magazine/ms681382(en-us,VS.85).aspx
第三种是do后执行语句后的返回值
这个经过测试只取最后一句的返回值
12 楼的 $xxx 输出是在 StdOut,不在 StdIn,所以 for /f 的输入仍然为空
一个小问题
$xxx 输出是在 stderr,而不是stdout,所以 for /f 的输入仍然为空
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |