批处理文件和DEL errorlevel 0问题

问题描述 投票:2回答:7

批处理必须从特定位置删除文件和目录,并将成功或stdout / stderr消息输出到新的.txt文件。我创建了大部分脚本,它完全按预期执行,除非删除成功,它会向前移动到下一行,而不是在日志上回显“成功”消息。

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:\NoSuchDirectory

GOTO :EOF

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

GOTO :EOF

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

GOTO :EOF

由于某种原因,我无法找到if del success echo'success'的语法。在上面的示例中,如果我删除该行

if errorlevel 0 echo successful

一切正常,但没有成功的消息。留下这条线就可以说明每一条线的成功。

batch-file echo delete-file errorlevel delete-directory
7个回答
9
投票

del and ErrorLevel?

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

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

Possible Work-Around

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

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

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

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

Explanation of Code

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

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

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

要明确设置ErrorLevel,您也可以使用cmd /C exit /B 1。也许这条线更清晰。确保它更灵活,因为你可以声明任何(带符号的32位)数字,包括0来清除它(省略数字也会清除它)。但是在性能方面可能会有点差。

Application Example

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

: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\newuser\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

Presetting ErrorLevel

除了上面提到的命令cmd /C exit /B,你也可以使用> nul ver来重置ErrorLevel。这可以与for /F循环解决方案结合使用,如下所示:

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

Alternative Method Without for /F

for /F命令也可以像STDERR一样使用,而不是使用del捕获findfind /V ""输出,ErrorLevel返回11,如果空字符串进来,del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1 否则:

ErrorLevel

但是,如果删除成功,这将返回1 0,如果没有,则返回if。要扭转这种行为,可以像这样添加else / 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

Different Approach: Checking File for Existance After Sasha

一种完全不同的方法是在尝试删除文件后检查文件是否存在(感谢hint的用户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) !),例如:

if errorlevel 0 echo successful

1
投票

使用此语法时,而不是此

if not errorlevel 1 echo successful

你可以使用它 - 因为errorlevel 0始终为true。

rm

1
投票

只需使用UnxUtils(或gowcygwin)的if %errorlevel% == 0 echo succesful 。如果文件不存在,或者删除文件时出错,它会正确设置errorlevel。


0
投票

到目前为止,我记得正确的语法是:

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:\NoSuchDirectory

GOTO :EOF

:delete
echo deleting %1
dir c:\users\newuser\Desktop\%1  >NUL 2>&1
SET existed=%ERRORLEVEL%
del /f /q c:\Users\newuser\Desktop\%1 
dir c:\users\newuser\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

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


0
投票

这是作为原始提问者的编辑添加的,我已将其转换为社区维基答案,因为它应该是答案,而不是编辑。

我发现了怎么做......无论如何都是这样。

http://www.robvanderwoude.com/errorlevel.php

0
投票

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

一个很好的参考是:>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.

:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1 
if errorlevel 1 (
    rem This block executes if ERRORLEVEL is a non-zero
    echo failed
) else (
    echo succesful
)

GOTO :EOF

我建议您将代码修改为以下内容:

:delete
echo deleting %1
del /f /q c:\Users\newuser\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

如果你需要处理多个ERRORLEVEL的东西,你可以这样做:

:delete
echo deleting %1
del /f /q c:\Users\newuser\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

要么

%~1

0
投票

aschipfl的答案很棒(谢谢,帮了我很多!)使用Presetting ErrorLevel下的代码你会得到一个很好的标准函数:

注意在%1语句中使用del而不是::###################################################################### ::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而不是qazxswpoi进行注释使代码更具可读性。

© www.soinside.com 2019 - 2024. All rights reserved.