"rd"在删除失败时会将错误级别设置为0。

15

我正在编写一个批处理(.bat)脚本,需要处理删除文件夹失败的情况。我使用%errorlevel%来捕获退出代码,但在rd命令的情况下似乎无法工作:

C:\Users\edo\Desktop>rd testdir
Directory is not empty

C:\Users\edo\Desktop>echo %errorlevel%
0

为什么?你有什么建议吗?

2个回答

28

哇,这是我见过的第二个ERRORLEVEL未正确设置的案例!请参见Windows中的文件重定向和%errorlevel%

解决方案与检测重定向失败的方法相同。使用||运算符以在出现错误时执行操作。

rd testdir || echo The command failed!

奇怪的是,当你使用 || 运算符时,如果文件夹不为空,ERRORLEVEL 将被正确设置为 145,如果文件夹不存在,则设置为 2。因此,你甚至不需要做任何事情。你可以有条件地“执行”一个备注,然后错误级别将被正确设置。

rd testdir || rem
echo %errorlevel%

我本以为上面的内容已经非常完整了,但下面一系列的评论揭示了在使用/RD /S时仍可能存在潜在问题。 如果父文件夹下的文件或子文件夹被锁定(任何级别下),那么RD /S /Q PARENT && echo removed || echo failed将会打印出一个错误信息,但是&&分支会执行,而不是||分支。非常不幸。如果由于父文件夹本身被锁定而导致命令失败,那么||将正确地触发并设置ERRORLEVEL。

可以通过交换stderr和stdout,并将结果管道到FINDSTR "^"来检测所有情况下的失败。如果找到匹配项,则一定存在错误。

3>&2 2>&1 1>&3 rd /s test | findstr "^" && echo FAILED

如果缺少/q选项,交换标准错误和标准输出非常重要,因为它允许"您确定吗(Y/N)?"提示在标准错误上可见,与标准输出上的错误消息隔离开来。


4
这对于代码2和145运行良好,但是在出现“访问被拒绝”或“由于另一个进程正在使用该文件,因此无法访问该文件”时,它只会使ERRORLEVEL保持不变。 :( - Andreas Vergison
1
帮了我大忙!谢谢... http://itados.blogspot.co.at/2015/04/dos-error-levels.html - Daniel Kienböck
1
这对我来说不适用于参数 /s。有人能确认一下吗? - Stefan
1
条件执行 || 如果一个内部文件夹因访问被阻止,则完全不起作用 Access is deniedRD 只具有 0 退出代码。 - it3xl
1
我认为@dbenham提到的例子仅适用于“拒绝访问”情况,因为它是一个非递归删除。这是关于“垃圾”目录本身而不是其内部的“拒绝访问”。如果“拒绝访问”是由目录内某个文件引起的,则ERRORLEVEL为0。我认为这可能是由于“del”中的错误函数(https://dev59.com/RH7aa4cB1Zd3GeqPrYYj)所致。也许在递归删除期间,Windows 尝试使用“del”删除目录内的每个文件,并且它总是不幸地返回0。 - Alexander Samoylov
显示剩余8条评论

10

rd命令不会将errorlevel(错误级别)设置为零,它会保留errorlevel的原始值:例如,如果之前的操作以正向的errorlevel结束,并且rd成功完成,则不会更改errorlevel。例如:robocopy中小于4的错误级别是警告而不是错误,可以忽略,因此即使目录已成功删除,以下代码也可能以错误结束:

robocopy ...
if errorlevel 4 goto :error
rd somedir
if errorlevel 1 goto :error
解决方案:忽略该错误,并检查在运行了rd命令后目录是否仍然存在:

解决方案:忽略错误并检查rd命令执行后目录是否仍然存在:

rd somedir
if exist somedir goto :error

2
关于 robocopy:在检查错误级别不大于4之后,请确保不要使用 set errorlevel=0 重置错误级别,因为此命令会创建一个环境变量,永久覆盖内部错误级别。请阅读这里 - rychu
这是我认为最好的解决方案。不要试图做复杂的变通,交换输出和其他垃圾来检测所有奇怪的情况...只需查看目录是否仍然存在;如果存在,则出现了问题。 - Doktor J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接