Batch file and DEL errorlevel 0 issue
Solution 1
del
and ErrorLevel
?
The del
command does not set the ErrorLevel
as long as the given arguments are valid, it even resets the ErrorLevel
to 0
in such cases (at least for Windows 7).
del
modifies the ErrorLevel
only in case an invalid switch is provided (del /X
sets ErrorLevel
to 1
), no arguments are specified at all (del
sets ErrorLevel
to 1
too), or an incorrect file path is given (del :
sets ErrorLevel
to 123
), at least for Windows 7.
Possible Work-Around
A possible work-around is to capture the STDERR
output of del
, because in case of deletion errors, the related messages (Could Not Find [...]
, Access is denied.
, The process cannot access the file because it is being used by another process.
) are written there. Such might look like:
for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
To use the code in command prompt directly rather than in a batch file, write %#
instead of %%#
.
If you do not want to delete read-only files, remove /F
from the del
command line;
if you do want prompts (in case wildcards ?
and/or *
are present in the file path), remove /Q
.
Explanation of Code
This executes the command line del /F /Q "\path\to\the\file_s.txt"
. By the part 2>&1 1> nul
, the command output at STDOUT
will be dismissed, and its STDERR
output will be redirected so that for /F
receives it.
If the deletion was successful, del
does not generate a STDERR
output, hence the for /F
loop does not iterate, because there is nothing to parse. Notice that ErrorLevel
will not be reset in that case, its value remains unchanged.
If for /F
recieves any STDERR
output from the del
command line, the command in the loop body is executed, which is set =
; this is an invalid syntax, therefore set
sets the ErrorLevel
to 1
. The 2> nul
portion avoids the message The syntax of the command is incorrect.
to be displayed.
To set the ErrorLevel
explicitly you could also use cmd /C exit /B 1
. Perhaps this line is more legible. For sure it is more flexible because you can state any (signed 32-bit) number, including 0
to clear it (omitting the number clears it as well). It might be a bit worse in terms of performance though.
Application Example
The following batch file demonstrates how the above described work-around could be applied:
: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
Besides the above mentioned command cmd /C exit /B
, you can also use > nul ver
to reset the ErrorLevel
. This can be combined with the for /F
loop work-around like this:
> 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
Instead of using for /F
to capture the STDERR
output of del
, the find
command could also be used like find /V ""
, which returns an ErrorLevel
of 1
if an empty string comes in and 0
otherwise:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1
However, this would return an ErrorLevel
of 1
in case the deletion has been successful and 0
if not. To reverse that behaviour, an if
/else
clause could be appended like this:
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 =)
Different Approach: Checking File for Existence After del
A completely different approach is to check the file for existence after having tried to delete it (thanks to user Sasha for the hint!), like this, for example:
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)
Solution 2
Just use rm
from UnxUtils (or gow or cygwin). It sets the errorlevel correctly in case of a nonexistent file, or any errors deleting the file.
Solution 3
When using this syntax, instead of this
if errorlevel 0 echo successful
you can use this - because errorlevel 0 is always true.
if not errorlevel 1 echo successful
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on June 22, 2022Comments
-
Admin about 2 years
The batch has to remove files and directories from specific locations and output success or stdout/stderr messages to a new .txt file. I have created the most of the script and it performs exactly as it should, except when the deletion is successful it moves forward to the next line rather than echo a 'successful' message on the log.
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
For some reason I can't find the syntax for if del succeeds echo 'successful'. In the above example if I remove the line
if errorlevel 0 echo successful
Everything works fine, but no success message. With this line left in it echoes success for every line.
-
Bob Stein about 5 yearsConfirm,
rm
sets errorlevel on a nonexistent file, whiledel
does not. -
Sasha almost 5 yearsWhy not just to check if file still exists after deletion attempt?
-
aschipfl almost 5 yearsSure, @Sasha, that is of course also possible; you could write your own answer to show how it could be done, if you want; or do you prefer me to extend mine instead?
-
Sasha almost 5 yearsIMHO it's better to have one comprehensive answer. So if you could extend yours it would be perfect.
-
lzhh about 3 years
2>&1 1> nul
might not achieve what you expected; should be1>nul 2>&1
.2>&1 1>nul
redirects STDERR to STDOUT, and what should've been in STDOUT toNUL
, i.e. only output STDERR to console. -
aschipfl about 3 years@lxvs, I intentionally used the expression
2>&1 1> nul
, because I want to capture STDERR byfor /F
and ignore STDOUT. The expression1> nul 2>&1
would suppress both STDOUT and STDERR, so there would be nothing left to capture… -
jifb almost 3 yearsTo exchange stdout and stderr, one can use
3>&2 2>&1 1>&3
(even in bash/sh). So the find approach could bedel /s /q "%~1" 3>&2 2>&1 1>&3 | find /V "" 3>&2 2>&1 1>&3 & if errorlevel 1 (1> nul ver) else (2> nul set =)