I have a batch file with 10 lines and 5 functions in a batch script. How can I ensure that all the commands in a batch file are successful.
In other way, what's the logic to calculate return code of each command at the end of a script.
1. #ECHO OFF
2. if not exist "%Destination%\%NAME%" md %Destination%\%NAME%
3. if not exist "%Destination%\%NAME2%" md %Destination%\%NAME2%
4. rmdir %Destination%\%NAME3%
5. if not exist "%Destination%\NAME4%" md %Destination%\%NAME4%
6. cd /d X:\test1
in the above 5 lines, 4th line returns %ERRORLEVEL% 1 and 6th line returns the same. But, I could not put IF %ERRORLEVEL%==0 after every command. So, how could i script to handle this.
You should firstly save your file as .cmd instead of .bat for better error handling. Also always enclose your paths with double quotes. Then I suggest you test existance as well to overcome errorlevel.
If exist "%Destination%\%NAME3%" rmdir "%Destination%\%NAME3%"
For the code example I suggest following:
#echo off
rem Verify the existence of all used environment variables.
for %%I in (Destination NAME NAME2 NAME3 NAME4) do (
if not defined %%I (
echo Error detected by %~f0:
echo/
echo Environment variable name %%I is not defined.
echo/
exit /B 4
)
)
rem Verify the existence of all used directories by creating them
rem independent on existing already or not and next verifying if
rem the directory really exists finally.
for %%I in ("%Destination%\%NAME%" "%Destination%\%NAME2%") do (
md %%I 2>nul
if not exist "%%~I\" (
echo Error detected by %~f0:
echo/
echo Directory %%I
echo does not exist and could not be created.
echo/
exit /B 3
)
)
rem Remove directories independent on their existence and verify
rem if the directories really do not exist anymore finally.
for %%I in ("%Destination%\%NAME3%") do (
rd /Q /S %%I 2>nul
if exist "%%~I\" (
echo Error detected by %~f0:
echo/
echo Directory %%I
echo still exists and could not be removed.
echo/
exit /B 2
)
)
cd /D X:\test1 2>nul
if /I not "%CD%" == "X:\test1" (
echo Error detected by %~f0:
echo/
echo Failed to set "X:\test1" as current directory.
echo/
exit /B 1
)
This batch file handles nearly all possible errors which could occur during execution of this batch file. A remaining problem could be caused by an environment variable containing one or more double quotes in its value. The solution would be using delayed expansion.
Linux shell script interpreters have the option -e to exit immediately execution of a script if any command or application returns with a value not equal 0. But Windows command interpreter cmd.exe does not have such an option. The options of cmd.exe can be read on running in a command prompt window cmd /?.
So it is necessary to use in a batch file:
if exist "..." exit /B 1 or goto :EOF
if not exist "..." exit /B 1 or goto :EOF
if errorlevel 1 exit /B 1 or goto :EOF
... || exit /B 1 or ... || goto :EOF
See also the Stack Overflow articles:
Windows batch files: .bat vs .cmd?
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file
What are the ERRORLEVEL values set by internal cmd.exe commands?
Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?
Related
I have come up with the following code which starts minimized, waits 5 seconds (for slow PC) deletes temp files after and should automatically close, but for some reason, automatic close is not working, .bat file stays minimized.
I tried using exit command but it has 0 effect because goto :EOF prevent it from execution, but if I will remove goto :EOF script won't delete temp files
if not DEFINED IS_MINIMIZED set IS_MINIMIZED=1 && start "" /min "%~dpnx0" %* && exit
PING localhost -n 5 >NUL
#echo off
setlocal
call :Clear_Folder %SystemRoot%\TEMP
pushd C:\Users
for /d %%k in (*) do if exist "%%k\AppData\Local\Temp" call :Clear_Folder "%%k\AppData\Local\Temp"
popd
endlocal
goto :EOF
:Clear_Folder
pushd "%~1"
for /d %%i in (*) do rd /s /q "%%i"
del /f /q *
popd
goto :EOF
exit
I'm looking forward to fix last step auto close, all other features work fine, the script starts minimized, it deletes temp files but after all of this it won't close itself and it stays minimized.
The reason your minimized script is not closing at the end is that you started the script directly, instead of as an argument to cmd.exe with it's /C option. When you run your script directly via Start, cmd.exe is run using the /K option with your batch file as its argument. When the /K option is used, as explained from running cmd /?, the window remains open upon completion of the command. To close that window you need to explicitly exit the cmd.exe instance:
Here's my take on what you intended to do:
#If Not Defined IS_MINIMIZED Set "IS_MINIMIZED=1"&Start "" /Min "%~f0"&Exit
#Echo Off
Timeout 5 /NoBreak>NUL
Call :Clear_Folder "%SystemRoot%\TEMP"
For /D %%k In ("C:\Users\*")Do If Exist "%%k\AppData\Local\Temp\" Call :Clear_Folder "%%k\AppData\Local\Temp"
Exit
:Clear_Folder
PushD "%~1" 2>NUL||Exit /B
RD /S /Q "%~1" 2>NUL
PopD
GoTo :EOF
If there's no other content beneath this, you can also remove GoTo :EOF
The goto eof statements are explicitly going to end of file, skipping anything else, including your exit statement. You therefore need to change or remove it, in this instance I added a different label to goto which has only exit in the label. The second loop does not require the goto as it will fall through the label regardless:
if not DEFINED IS_MINIMIZED set IS_MINIMIZED=1 && start "" /min "%~dpnx0" %* && exit
timeout 5>nul
#echo off
setlocal
call :Clear_Folder %SystemRoot%\TEMP
pushd C:\Users
for /d %%k in (*) do if exist "%%k\AppData\Local\Temp" call :Clear_Folder "%%k\AppData\Local\Temp"
popd
endlocal
exit
:Clear_Folder
pushd "%~1"
for /d %%i in (*) do rd /s /q "%%i"
del /f /q *
popd
To explain: goto :eof is a predefined label that will exit the current script or subroutine. It therefore will skip anything in the script and simply stops executing any further instructions.
See this link on ss64
The problem is the first line not explicitly starting cmd.exe with option /C to execute the batch file once again with a separate command process with minimized window.
#echo off
if defined IS_MINIMIZED goto ClearFolders
set "IS_MINIMIZED=1"
start "Clear Folders" /min %ComSpec% /C "%~f0" %*
goto :EOF
:ClearFolders
call :Clear_Folder "%SystemRoot%\TEMP"
if defined TEMP call :Clear_Folder "%TEMP%"
for /D %%k in (C:\Users\*) do if exist "%%k\AppData\Local\Temp" call :Clear_Folder "%%k\AppData\Local\Temp"
goto :EOF
:Clear_Folder
pushd "%~1"
if errorlevel 1 goto :EOF
rd /Q /S "%~1" 2>nul
popd
goto :EOF
See also my answer on How to delete files/subfolders in a specific directory at the command prompt in Windows? It explains why rd /Q /S "%~1" 2>nul is enough to delete all subfolders and files in directory of which path is passed with argument 1 to the subroutine Clear_Folder if that directory is really existing and pushd successfully made it the current directory for the command process processing the batch file.
See also: Where does GOTO :EOF return to?
What happens after execution of first goto :EOF depends on how this batch file was started and in which environment.
A double click on a batch file results in starting the Windows command processor cmd.exe for processing the batch file with using implicit option /C to close command process after execution of the batch file. In this case the first goto :EOF results in closing initially opened console window as the Windows command process processing the batch file initially also closes.
Opening first a command prompt window results in starting cmd.exe with using implicit option /K to keep command process running after execution of a command line like executing this batch file. In this case the console window remains open after execution of first goto :EOF as the command process keeps running for further command executions by the user.
The first goto :EOF could be replaced by command exit to always exit the command process independent on how cmd.exe initially processing the batch file was started and independent on the calling hierarchy. So the usage of exit is not advisable in case of this batch file is called from another batch file which does for example more hard disk cleanup operations.
I have batch script that reads form a Unix shared directory (X) every 3 seconds, and copies all files to a local directory on Windows 7 PC.
Once files have successfully copied the script deletes the contents of the Unix share directory so the same files are not copied again.
The issue is the script occasionally fails to copy a file.
This appears to be quite random.
The script should throw any encountered errors but I do not see any errors on the output log when these events occur.
So my questions are:
1. Is there an issue with my script regarding error catching. The log only ever has output based on the errorLevel of 0 (see script), even when there are no files in the Unix directory, where errorLevel 1 output to log should execute according to code.
Is there a reason files would not be copied from a shared unix directory to a local directory in what appears to be a random manner?
Any input appreciated.
echo off
:START
rem /Y removes prompt fro do you want to overwrite?
xcopy /Y X:\ C:\Users\histology\Desktop\PrintMateCopy
rem for debugging missed cassettes, copy to a new directory and don't delete
xcopy /Y X:\ C:\Users\histology\Desktop\PrintmateCopy2
echo %errorLevel%
if %errorLevel% equ 5 (
echo Disk write error occurred.: Error %errorLevel% >> PrintMateLog.log
)
if %errorLevel% equ 4 (
echo %date% : %time% : Error: %errorLevel% : Initialization error occurred. There is not
enough memory or disk space, or you entered
an invalid drive name or invalid syntax on
the command line. >> C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log
)
if %errorLevel% equ 2 (
echo Error: %errorLevel% user terminated the copy with Crtl C >> C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log
)
if %errorLevel% equ 1 (
echo Error: %errorLevel% No files found >> C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log
)
if %errorLevel% equ 0 (
echo %date% : %time% : Files were copied without error. Deleting Unix share files from dir..Errorlevel : %errorLevel% >> C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log
rem /F Force del read only files. /Q force del without prompt
del /F /Q X:\
if %errorLevel% equ 1 (
echo No Unix share dir files found. error %errorLevel% C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log
)
if %errorLevel% equ 0 (
echo Files deleted.>> C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log
)
)
ADDITION : Script to count the number of files in the directory before a copy has been made.
Issue is the script pauses when the directory is empty, is there a means to check if the directory is empty before the code is executed?
SET /A "N=0"
FOR /F %%f IN ('DIR /S /B /A:-D "*"') DO (
SET /A "N=!N!+1"
)
ECHO N is %N%
Perhaps give this version a try. We do not need to parenthesize a single command, if statements, lastly, your printmate.log had 2 different versions, one with path and one without, let's try and keep a standard. Please copy code exactly as is:
echo off
rem /Y removes prompt fro do you want to overwrite?
xcopy /Y X:\ C:\Users\histology\Desktop\PrintMateCopy
rem for debugging missed cassettes, copy to a new directory and don't delete
xcopy /Y X:\ C:\Users\histology\Desktop\PrintmateCopy2
echo %errorLevel%
if %errorLevel% equ 5 echo Disk write error occurred.: Error %errorLevel%>>.>>"C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log"
if %errorLevel% equ 4 echo %date% : %time% : Error: %errorLevel% : Initialization error occurred. There is not enough memory or disk space, or you entered an invalid drive name or invalid syntax on the command line.>>"C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log"
if %errorLevel% equ 2 echo Error: %errorLevel% user terminated the copy with Crtl C>>"C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log"
if %errorLevel% equ 1 echo Error: %errorLevel% No files found>>"C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log"
if %errorLevel% equ 0 goto :delfiles
Goto :EOF
:delfiles
echo %date% : %time% : Files were copied without error. Deleting Unix share files from dir..Errorlevel : %errorLevel%>>"C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log"
del /F /Q X:\
If %errorlevel% equ 0 (
echo files deleted successfully>>"C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log"
) else (
echo error deleting files>>"C:\Users\histology\Desktop\PrintmateCopy2\PrintMateLog.log"
)
Edit
As per your comment, perhaps we can just check for the file count in x:\ plus the file count in c:\ then move all files and check if the file count in c:
\ is the same after the move, if not retry.
#echo off
:start
set "home_path=C:\Users\histology\Desktop\PrintMateCopy"
for /f %%i in ('dir /a-d-s-h /b X:\ ^| find /v /c ""') do echo set xcnt=%%i
for /f %%i in ('dir /a-d-s-h /b "%home_path%" ^| find /v /c ""') do echo set ccnt=%%i
set /a compcount=xcnt+ccnt
move /Y X:\* "%home_path%
for /f %%i in ('dir /a-d-s-h /b %home_path% ^| find /v /c ""') do echo set mvcnt=%%i
if "%mvcnt%"=="%compcont%" (
echo All files moved
) else (
echo not all files moved %mvcnt% files remains
goto :start
)
EDIT: I have updated this post to include the entire script.
EDIT: While not ideal, this is meant to be an automation of a fix provided by the company that makes the software.
I have a batch file that I am running as Administrator.
I am running a batch file based on the file system input by the user.
One of the first commands renames a file.
If I execute this command on its own, from an elevated command prompt, it renames the file.
When I nest the command inside the IF statement, it doesn't rename the file.
I have commented out all of the other lines to simply rename the file if the user enters "1".
I have tried encapsulating the file path and file each individually within quotes, which I shouldn't need, and still do not get it to rename the file.
I am running the batch script as Admin.
#echo off
setlocal EnableDelayedExpansion
if "%$ecbId%" == "" (
echo Welcome to the ADaPT
echo Choose '1' for 32 bit
echo Choose '2' for 64 bit
echo Type anything else to abort.
echo.
set "UserChoice=abort"
set /P "UserChoice=Type your choice: "
if "!UserChoice!"=="1" (
echo Executing 32 bit sequence...
echo Regsvr32.exe /u C:\Windows\System32\MSCOMCTL.OCX
echo REN C:\Windows\System32\MSCOMCTL.OCX MSCOMCTL.bak
xcopy C:\install\MSCOMCTL.OCX C:\Windows\System32 folder
Regsvr32.exe C:\Windows\System32\MSCOMCTL.OCX
Regsvr32.exe /u C:\Windows\System32\MSCOMCTL.OCX
del "C:\Windows\System32\ MSCOMCTL.OCX"
echo REN "C:\Windows\System32\MSCOMCTL.bak" "MSCOMCTL.OCX"
Recho Regsvr32.exe C:\Windows\System32\MSCOMCTL.OCX
shutdown.exe /r /t 00
)
if "!UserChoice!"=="2" (
echo Regsvr32.exe /u C:\Windows\SYSWOW64\MSCOMCTL.OCX
echo REN "C:\Windows\SYSWOW64\MSCOMCTL.OCX" "MSCOMCTL.bak"
xcopy C:\install\MSCOMCTL.OCX C:\Windows\SYSWOW64 folder
Regsvr32.exe C:\Windows\SYSWOW64\MSCOMCTL.OCX
Regsvr32.exe /u C:\Windows\SYSWOW64\MSCOMCTL.OCX
del "C:\Windows\SYSWOW64\ MSCOMCTL.OCX"
echo REN "C:\Windows\SYSWOW64\MSCOMCTL.bak" "MSCOMCTL.OCX"
echo Regsvr32.exe C:\Windows\SYSWOW64\MSCOMCTL.OCX
REM... shutdown.exe /r /t 00
)
if not "!UserChoice!"=="1" (
echo toto3
if not "!UserChoice!"=="2" (
echo toto4
echo Unknown input ... Aborting script
endlocal
exit /B 400
)
)
)
endlocal
I have simplified your entire script structure so as not to require parenthesised blocks, or the need to delay expansion:
#Echo Off
If Defined $ecbId GoTo :EOF
Echo Welcome to the ADaPT
Choice /C CQ /M "Continue or Quit"
If ErrorLevel 2 GoTo :EOF
Set "Dest=TEM32"
Set PROCESSOR_ARCHITE|Find "64">Nul&&(Set Dest=WOW64)
Set "Dest=%SYSTEMROOT%\SYS%Dest%"
Echo Executing sequence . . .
RegSvr32 /U "%Dest%\MSCOMCTL.OCX"
Rem To backup and replace MSCOMCTL.OCX:
Rem Uncomment the next three unRemarked lines
Rem and comment the next three unRemarked lines below them.
::Del /A /F "MSCOMCTL.bak" 2>Nul
::Ren "%Dest%\MSCOMCTL.OCX" "MSCOMCTL.bak"
::XCopy "C:\install\MSCOMCTL.OCX" "%Dest%"
Rem To recover MSCOMCTL.OCX from the backup:
Rem Comment the next three unRemarked lines
Rem and uncomment the previous three unRemarked lines above them.
If Not Exist "MSCOMCTL.bak" RegSvr32 "%Dest%\MSCOMCTL.OCX" & GoTo :EOF
Del /A /F "%Dest%\MSCOMCTL.OCX"
Ren "%Dest%\MSCOMCTL.bak" "MSCOMCTL.OCX"
RegSvr32 "%Dest%\MSCOMCTL.OCX"
ShutDown /R /T 0 /D P:2:4
Notes:It is probably safe to delete lines 3 and empty line 4, I left them in only because no explanation was provided as to the purpose of the %$ecbId% variable value comparison.I have added Remarks for toggling the script for the backup or recovery methods, but not knowingly altered any of your command sequence, (I have however added the /A and /F options with Del, just in case, and included the /D option with ShutDown to ensure that the logs show it as a planned shutdown event).
I am creating a batch for creation of zip files from folders, I want to check if the zip file has been created succesfully. It does the logging of which zip file has been created but when it goes wrong it should goto a label and stop the operation. This does not work, the ELSE command is echoed and not executed.
SETLOCAL EnableExtensions EnableDelayedExpansion
for /d %%d in (*) do (
"7z.exe" a -r -tzip "%%d.zip" ".\%%d\" & IF %ERRORLEVEL% EQU 0 (echo Archive "%%d.zip" created succesfully >> "Archive-log %date%.txt") ELSE (set fault="%%d.zip" goto createzip))
exit /b
:createzip
echo Failed creating archive %fault% >> "Error-log %date%.txt"
exit /b
Here is the batch code rewritten and extended. The batch file does not immediately stop on failing to compress a subfolder to a ZIP archive.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Get current date in region dependent format with . as delimiter.
set "FileDate=%DATE:/=.%"
set "ErrorCount=0"
set "FolderCount=0"
rem Compress each non hidden subfolder in current folder into a ZIP file.
for /D %%I in (*) do (
set /A FolderCount+=1
"7z.exe" a -r -tzip "%%I.zip" ".\%%I\"
if errorlevel 1 (
echo Failed creating archive: "%%I.zip">>"Error-log %FileDate%.txt"
set /A ErrorCount+=1
) else (
echo Archive "%%I.zip" created succesfully.>>"Archive-log %FileDate%.txt"
)
)
rem Exit batch processing if no subfolder was found in current folder?
if %FolderCount% == 0 endlocal & exit /B
set "ErrorPluralS=s"
if %ErrorCount% == 1 set "ErrorPluralS="
set "FolderPluralS=s"
if %FolderCount% == 1 set "FolderPluralS="
echo Processed %FolderCount% folder%FolderPluralS% with %ErrorCount% error%ErrorPluralS%.>>"Archive-log %FileDate%.txt"
endlocal
if errorlevel 1 working also without usage of delayed expansion means:
IF the exit code of the previous command or executable is greater or equal 1 THEN ...
This is explained in the Microsoft support article Testing for a Specific Error Level in Batch Files and working from MS-DOS to Windows 10 in batch files and on command line.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
for /?
if /?
rem /?
set /?
setlocal /?
Read also the answers on:
Single line with multiple commands using Windows batch file
How to get information about current path %CD% in batch in a FOR loop?
I think it's because your ELSE contains 2 statements which aren't separated so the goto ends up being part of the set command. To fix that and for readability, I think you should reformat a bit:
for /d %%d in (*) do (
"7z.exe" a -r -tzip "%%d.zip" ".\%%d\"
IF %ERRORLEVEL% EQU 0 (
echo Archive "%%d.zip" created succesfully >> "Archive-log %date%.txt"
) ELSE (
set fault="%%d.zip"
goto createzip
)
)
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.
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)
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
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.
This was added as an edit by the original asker, I have converted it to a community wiki answer because it should be an answer, not an edit.
I found out how to do it... one way anyway.
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
IF ERRORLEVEL 0 [cmd] will execute every time because IF ERRORLEVEL # checks to see if the value of ERRORLEVEL is greater than or equal to #. Therefore, every error code will cause execution of [cmd].
A great reference for this is: http://www.robvanderwoude.com/errorlevel.php
>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.
I would recommend modifying your code to something like the following:
: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
If you need something that processes more than one ERRORLEVEL, you could do something like this:
: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
OR
: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
The answer of aschipfl is great (thanks, helped me a lot!) using the code under Presetting ErrorLevel you get a nice standard function:
Take care to use %~1 instead of %1 in the del statement, or you will get errors if you use a quoted filename.
::######################################################################
::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
BTW 1: You can give a nifty error message as a second parameter
BTW 2: Using :: instead of REM for comments makes the code even more readable.
Code:
Error Code: (What you did)
if errorlevel 0 echo succesful
The problem here is that you aren't calling errorlevel as a variable and plus you didn't add in the operator to the statement as well.
Correct Code: (Here is what it should actually be.)
if %ERRORLEVEL% EQU 0 echo succesful
Definitions:
EQU: The EQU stands for Equal. This kind of operator is also called a relational operator. Here is the documentation link to operators if you wanna know more, there are other ones but this helped me.
ERRORLEVEL: is declared as a variable and usually get the error level of the last command run usually. Variables are usually called when they are between percent signs like this
%foo%
For some more help on variables, go to cmd (Which you can go to by searching it on windows 10) and type in "set /?", without the quotes. the set command is the command you use to set variables