关于cmd:批处理文件和DEL错误级别0问题

Batch file and DEL errorlevel 0 issue

批处理必须从特定位置删除文件和目录,并将成功或stdout / stderr消息输出到新的.txt文件。 我已经创建了大部分脚本,并且脚本的运行情况与应该的完全一样,只是删除成功后,脚本会前进到下一行,而不是在日志中回显"成功"消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
echo Basic Deletion Batch Script > results.txt
@echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b

:filelog

call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:
oSuchDirectory

GOTO :EOF

:delete
echo deleting %1
del /f /q c:\Users
ewuser\Desktop\%1
if errorlevel 0 echo succesful

GOTO :EOF

:remove
echo deleting directory %1
rmdir /q /s %1

GOTO :EOF

由于某种原因,我找不到del成功返回echo'successful'的语法。 在上面的示例中,如果我删除了该行

1
if errorlevel 0 echo successful

一切正常,但没有成功消息。 保留这条线,这回响每条线的成功。


delErrorLevel

只要给定参数有效,del命令就不会设置ErrorLevel,在这种情况下(至少对于Windows 7),它甚至会将ErrorLevel重置为0

del仅在提供无效开关(del /XErrorLevel设置为1),根本不指定任何参数(del还将ErrorLevel设置为1)的情况下修改ErrorLevel。 ,或者给出了错误的文件路径(del :ErrorLevel设置为123),至少对于Windows 7是这样。

可能的工作

可能的解决方法是捕获delSTDERR输出,因为在删除错误的情况下,相关消息(Could Not Find [...]Access is denied.The process cannot access the file because it is being used by another process.)被写入此处。这样可能看起来像:

1
for /F"tokens=*" %%# in ('del /F /Q"\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)

若要直接在命令提示符下而不是在批处理文件中使用该代码,请写%#而不是%%#

如果您不想删除只读文件,请从del命令行中删除/F
如果确实要提示(如果文件路径中存在通配符?和/或*),请删除/Q

代码说明

这将执行命令行del /F /Q"\path\to\the\file_s.txt"。通过2>&1 1> nul部分,将取消STDOUT处的命令输出,并将其STDERR输出重定向,以便for /F接收它。

如果删除成功,则del不会生成STDERR输出,因此for /F循环不会迭代,因为没有要解析的内容。请注意,在这种情况下,ErrorLevel不会被重置,其值保持不变。

如果for /F接收到del命令行的任何STDERR输出,则执行循环主体中的命令,即set =;这是无效的语法,因此setErrorLevel设置为12> nul部分避免显示消息The syntax of the command is incorrect.

要显式设置ErrorLevel,您还可以使用cmd /C exit /B 1。也许这条线更清晰。可以肯定地说,它更加灵活,因为您可以声明任何(带符号的32位)数字,包括0可以清除它(省略该数字也可以清除它)。但是在性能方面可能会更糟。

应用范例

以下批处理文件演示了如何应用上述替代方法:

1
2
3
4
5
6
7
8
9
10
:DELETE
echo Deleting"%~1"...
rem this line resets ErrorLevel initially:
cmd /C exit /B
rem this line constitutes the work-around:
for /F"tokens=*" %%# in ('del /F /Q"C:\Users
ewuser\Desktop\%~1" 2^>^&1 1^> nul') do (2> nul set =)
rem this is the corrected ErrorLevel query:
if not ErrorLevel 1 echo Deleted"%~1" succesfully.
goto :EOF

预设ErrorLevel

除了上述命令cmd /C exit /B,您还可以使用> nul ver重置ErrorLevel。可以将其与for /F循环解决方法结合使用,如下所示:

1
> nul ver & for /F"tokens=*" %%# in ('del /F /Q"\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)

没有for /F的替代方法

除了使用for /F来捕获delSTDERR输出之外,还可以像find /V""一样使用find命令,如果输入空字符串,则返回1ErrorLevel并< x10>否则:

1
del"\path\to\the\file_s.ext" 2>&1 1> nul | find /V"" 1> nul 2>&1

但是,如果删除成功,这将返回1ErrorLevel,否则返回0。为了扭转这种行为,可以像这样附加if / else子句:

1
del"\path\to\the\file_s.ext" 2>&1 1> nul | find /V"" 1> nul 2>&1 & if ErrorLevel 1 (1> nul ver) else (2> nul set =)

不同的方法:del之后检查文件是否存在

完全不同的方法是在尝试删除文件后检查文件是否存在(感谢用户Sasha的提示!),例如:

1
2
del /F /Q"\path\to\the\file_s.txt" 1> nul 2>&1
if exist"\path\to\the\file_s.txt" (2> nul set =) else (1> nul ver)


只需使用UnxUtils(或gow或cygwin)中的rm。如果文件不存在或删除文件时出现任何错误,它将正确设置错误级别。


使用此语法时,请使用此语法

1
if errorlevel 0 echo successful

您可以使用它-因为错误级别0始终为true。

1
if not errorlevel 1 echo successful

使用Presetting ErrorLevel下的代码,aschipfl的答案很好(谢谢,对我有很大帮助!),您会得到一个不错的标准函数:

注意在del语句中使用%~1而不是%1,否则,如果使用带引号的文件名,则会出现错误。

1
2
3
4
5
6
7
8
::######################################################################
::call :DELETE"file.txt"
::call :DELETE"file.txt""error message"
:DELETE
  >nul ver && for /F"tokens=*" %%# in ('del /F /Q"%~1" 2^>^&1 1^> nul') do (2>nul set =) || (
    if NOT .%2==. echo %~2
  )
goto :EOF

顺便说一句:您可以给一个漂亮的错误消息作为第二个参数
顺便说一句2:使用::而不是REM进行注释使代码更具可读性。


IF ERRORLEVEL 0 [cmd]每次都会执行,因为IF ERRORLEVEL#检查ERRORLEVEL的值是否大于或等于#。因此,每个错误代码都会导致执行[cmd]。

一个很好的参考是:http://www.robvanderwoude.com/errorlevel.php

1
2
3
4
5
6
7
8
9
10
11
12
13
>IF /?
Performs conditional processing in batch programs.

IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command

  NOT               Specifies that Windows should carry out
                    the command only if the condition is false.

  ERRORLEVEL number Specifies a true condition if the last program run
                    returned an exit code equal to or greater than the number
                    specified.

我建议将您的代码修改为如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
:delete
echo deleting %1
del /f /q c:\Users
ewuser\Desktop\%1
if errorlevel 1 (
    rem This block executes if ERRORLEVEL is a non-zero
    echo failed
) else (
    echo succesful
)

GOTO :EOF

如果您需要处理多个错误级别的内容,则可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
:delete
echo deleting %1
del /f /q c:\Users
ewuser\Desktop\%1
if errorlevel 3 echo Cannot find path& GOTO :delete_errorcheck_done
if errorlevel 2 echo Cannot find file& GOTO :delete_errorcheck_done
if errorlevel 1 echo Unknown error& GOTO :delete_errorcheck_done
echo succesful
:delete_errorcheck_done

GOTO :EOF

要么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
:delete
echo deleting %1
del /f /q c:\Users
ewuser\Desktop\%1
goto :delete_error%ERRORLEVEL% || goto :delete_errorOTHER

:delete_errorOTHER
echo Unknown error: %ERRORLEVEL%
GOTO :delete_errorcheck_done
:delete_error3
echo Cannot find path
GOTO :delete_errorcheck_done
:delete_error2
echo Cannot find file
GOTO :delete_errorcheck_done
:delete_error0
echo succesful
:delete_errorcheck_done

GOTO :EOF

这是原始询问者添加的编辑内容,我将其转换为社区Wiki答案,因为它应该是答案,而不是编辑内容。

无论如何,我找到了方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
echo Startup > results.txt
@echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b

:filelog

call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:
oSuchDirectory

GOTO :EOF

:delete
echo deleting %1
dir c:\users
ewuser\Desktop\%1  >NUL 2>&1
SET existed=%ERRORLEVEL%
del /f /q c:\Users
ewuser\Desktop\%1
dir c:\users
ewuser\Desktop\%1 2>NUL >NUL
if %existed% == 0 (if %ERRORLEVEL% == 1  echo"successful" )

GOTO :EOF

:remove
echo deleting directory %1
rmdir /q /s %1

GOTO :EOF


据我所知,正确的语法是:

1
if %errorlevel% == 0 echo succesful

百分号是检查环境变量的提示。