How to conditionally take action if FINDSTR fails to find a string - windows

I have a batch file as follows;
CD C:\MyFolder
findstr /c:"stringToCheck" fileToCheck.bat
IF NOT XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y
I am getting an error ("C:\OtherFolder\fileToCheck.bat" was unexpected at this time.) when trying to execute this.
Please let me know what I am doing wrong.

I presume you want to copy C:\OtherFolder\fileToCheck.bat to C:\MyFolder if the existing file in C:\MyFolder is either missing entirely, or if it is missing "stringToCheck".
FINDSTR sets ERRORLEVEL to 0 if the string is found, to 1 if it is not. It also sets errorlevel to 1 if the file is missing. It also prints out each line that matches. Since you are trying to use it as a condition, I presume you don't need or want to see any of the output. The 1st thing I would suggest is to redirect both the normal and error output to nul using >nul 2>&1.
Solution 1 (mostly the same as previous answers)
You can use IF ERRORRLEVEL N to check if the errorlevel is >= N. Or you can use IF NOT ERRORLEVEL N to check if errorlevel is < N. In your case you want the former.
findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1
if errorlevel 1 xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder"
Solution 2
You can test for a specific value of errorlevel by using %ERRORLEVEL%. You can probably check if the value is equal to 1, but it might be safer to check if the value is not equal to 0, since it is only set to 0 if the file exists and it contains the string.
findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1
if not %errorlevel% == 0 xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder"
or
findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1
if %errorlevel% neq 0 xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder"
Solution 3
There is a very compact syntax to conditionally execute a command based on the success or failure of the previous command: cmd1 && cmd2 || cmd3 which means execute cmd2 if cmd1 was successful (errorlevel=0), else execute cmd3 if cmd1 failed (errorlevel<>0). You can use && alone, or || alone. All the commands need to be on the same line. If you need to conditionally execute multiple commands you can use multiple lines by adding parentheses
cmd1 && (
cmd2
cmd3
) || (
cmd4
cmd5
)
So for your case, all you need is
findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1 || xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder"
But beware - the || will respond to the return code of the last command executed. In my earlier pseudo code the || will obviously fire if cmd1 fails, but it will also fire if cmd1 succeeds but then cmd3 fails.
So if your success block ends with a command that may fail, then you should append a harmless command that is guaranteed to succeed. I like to use (CALL ), which is harmless, and always succeeds. It also is handy that it sets the ERRORLEVEL to 0. There is a corollary (CALL) that always fails and sets ERRORLEVEL to 1.

You are not evaluating a condition for the IF. I am guessing you want to not copy if you find stringToCheck in fileToCheck. You need to do something like (code untested but you get the idea):
CD C:\MyFolder
findstr /c:"stringToCheck" fileToCheck.bat
IF NOT ERRORLEVEL 0 XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y
EDIT by dbenham
The above test is WRONG, it always evaluates to FALSE.
The correct test is IF ERRORLEVEL 1 XCOPY ...
Update: I can't test the code, but I am not sure what return value findstr actually returns if it doesn't find anything. You might have to do something like:
CD C:\MyFolder
findstr /c:"stringToCheck" fileToCheck.bat > tempfindoutput.txt
set /p FINDOUTPUT= < tempfindoutput.txt
IF "%FINDOUTPUT%"=="" XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y
del tempfindoutput.txt

In DOS/Windows Batch most commands return an exitCode, called "errorlevel", that is a value that customarily is equal to zero if the command ends correctly, or a number greater than zero if ends because an error, with greater numbers for greater errors (hence the name).
There are a couple methods to check that value, but the original one is:
IF ERRORLEVEL value command
Previous IF test if the errorlevel returned by the previous command was GREATER THAN OR EQUAL the given value and, if this is true, execute the command. For example:
verify bad-param
if errorlevel 1 echo Errorlevel is greater than or equal 1
echo The value of errorlevel is: %ERRORLEVEL%
Findstr command return 0 if the string was found and 1 if not:
CD C:\MyFolder
findstr /c:"stringToCheck" fileToCheck.bat
IF ERRORLEVEL 1 XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y
Previous code will copy the file if the string was NOT found in the file.
CD C:\MyFolder
findstr /c:"stringToCheck" fileToCheck.bat
IF NOT ERRORLEVEL 1 XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y
Previous code copy the file if the string was found. Try this:
findstr "string" file
if errorlevel 1 (
echo String NOT found...
) else (
echo String found
)

I tried to get this working using FINDSTR, but for some reason my "debugging" command always output an error level of 0:
ECHO %ERRORLEVEL%
My workaround is to use Grep from Cygwin, which outputs the right errorlevel (it will give an errorlevel greater than 0) if a string is not found:
dir c:\*.tib >out 2>>&1
grep "1 File(s)" out
IF %ERRORLEVEL% NEQ 0 "Run other commands" ELSE "Run Errorlevel 0 commands"
Cygwin's grep will also output errorlevel 2 if the file is not found. Here's the hash from my version:
C:\temp\temp>grep --version
grep (GNU grep) 2.4.2
C:\cygwin64\bin>md5sum grep.exe
c0a50e9c731955628ab66235d10cea23 *grep.exe
C:\cygwin64\bin>sha1sum grep.exe
ff43a335bbec71cfe99ce8d5cb4e7c1ecdb3db5c *grep.exe

Related

Clear or reset ERRORLEVEL in a Windows batch script [duplicate]

I have a post-build event that runs some commands for a c# project. The last command would sometimes cause the ERRORLEVEL value not equals to zero and then the build fails.
I want to append an extra line of command to always set the ERRORLEVEL value to zero. What is the most convenient way to do that?
if you use exit /b 0 you can return an errorlevel 0 from within a child batch script without also exiting the parent.
Seems to do the trick:
ver > nul
Not everything works, and it is not clear why. For example, the following do not:
echo. > nul
cls > nul
In a pre- or post-build event, if the return code of an executable is greater than zero, and the call to the executable is not the last line of the pre- or post-build event, a quick way to mute it and avoid triggering a check for a non-zero errorlevel is to follow the failing line with a line that explicitly returns zero:
cmd /c "exit /b 0"
This is essentially a generic combination of the previously-mentioned solutions that will work with more than just the last line of a pre- or post-build event.
I personally use this:
cd .
Works even in unix shell.
But, this one might be a bit faster:
type nul>nul
Because Process Monitor shows QueryDirectory calls on cd .
PS:
cd . has another nice side effect in the unix shell. It does restore recreated working directory in the terminal if it has been opened before the erase.
Update:
And that is a bit more faster:
call;
Any windows command to find if a file is in use or not ? :https://www.dostips.com/forum/viewtopic.php?t=5542
I found that "exit 0" looks like a good way to deal with this problem.
Usage Example:
NET STOP UnderDevService /Y
exit 0
if the UnderDevService service is not started.
I use VERIFY or VERIFY > nul
If this is a snippet like "Post-build Event" etc., then you'll be fine appending:
(...) || ver > nul
at the end of the last command.
Alternatively
cmd /c "exit /b 0"
is very clean and non-idiomatic -- a reader who knows Windows shell will know what's going on, and what was your intent.
However, if you're in a batch script, you may want to use subrotines, which are a lightweight equivalent of the "child batch script" from akf's answer.
Have a subroutine:
:reset_error
exit /b 0
and then just
call :reset_error
wherever you need it.
Here's a complete example:
#echo off
rem *** main ***
call :raise_error
echo After :raise_error ERRORLEVEL = %ERRORLEVEL%
call :empty
echo After :empty ERRORLEVEL = %ERRORLEVEL%
call :reset_error
echo After :reset_error ERRORLEVEL = %ERRORLEVEL%
:: this is needed at the end of the main body of the script
goto:eof
rem *** subroutines ***
:empty
goto:eof
:raise_error
exit /b 1
:reset_error
exit /b 0
Which outputs:
After :raise_error ERRORLEVEL = 1
After :empty ERRORLEVEL = 1
After :reset_error ERRORLEVEL = 0
As you see - just calling and returning via goto:eof is not enough.
The following works in modern Windows (NT-based) systems that feature cmd.exe:
rem /* This clears `ErrorLevel`; the SPACE can actually be replaced by an
rem arbitrary sequence of SPACE, TAB, `,`, `;`, `=`, NBSP, VTAB, FF: */
(call )
The SPACE (or more precisely, an arbitrary sequence of one or more standard token separators, which are SPACE (code 0x20), TAB (code 0x09), ,, ;, =, NBSP (code 0xFF), VTAB (code 0x0B) and FF (code 0x0C)) is mandatory; if you omit it the ErrorLevel becomes set instead:
rem // This sets `ErrorLevel` to `1`:
(call)
There is a nice thread on DosTips.com where this technique came up.
Here is an alternative method, but which accesses the file system and might therefore be a bit slower:
dir > nul
rem /* Perhaps this is a little faster as a specific file is given rather
rem than just the current directory (`.` implicitly) like above: */
dir /B "%ComSpec%" > nul
Here are some other ways to reset the ErrorLevel state, which even work in MS-DOS (at least for version 6.22):
more < nul > nul
rem // The `> nul` part can be omitted in Windows but is needed in MS-DOS to avoid a line-break to be returned:
sort < nul > nul
The following methods work in MS-DOS only:
command /? > nul
fc nul nul > nul
keyb > nul
For the sake of completeness, this sets the ErrorLevel state to 1, valid for both Windows and MS-DOS:
< nul find ""
After reviewing all of the other answers, I decided to find which way was the most efficient for resetting the ERRORLEVEL. I made a quick script that recorded the time to execute each of these:
"cmd /c "exit /b 0"", "cd .", "ver", "type nul", and "VERIFY"
here is the output:
cmd /v:on /c set ^"q=^"^" & timeit.cmd "cmd /c ^!q^!exit /b 0^!q^!" "cd ." "ver" "type nul" "VERIFY"
cmd /c "exit /b 0" took 0:0:0.02 (0.02s total)
cd . took 0:0:0.00 (0.00s total)
Microsoft Windows [Version 10.0.18362.836]
ver took 0:0:0.00 (0.00s total)
type nul took 0:0:0.00 (0.00s total)
VERIFY is off.
VERIFY took 0:0:0.00 (0.00s total)
This took 0:0:0.06 (0.06s total)
after reviewing with Measure-Command {command} in Powershell, I found that it only really accepted cd . and cmd /c "exit /b 0" --am I doing something wrong?
I'd recommend either cd . or type nul since neither have a footprint on the output of the console, nor are they slow in any measure.
yeah I'm pretty bored
Add >nul after each command that's likely to fail - this seems to prevent the build from failing.
You can still check the result of the command by examining %errorlevel%.
For example:
findstr "foo" c:\temp.txt>nul & if %errorlevel% EQU 0 (echo found it) else (echo didn't find it)
I'm using this:
ping localhost -n 1 >null
I always just used;
set ERRORLEVEL=0
I've been using it for donkey's years.

Exist, Rmdir and %errorlevel% in batch Windows [duplicate]

I'm writing a batch (.bat) script and I need to handle the case in which the deletion of a folder fails. I'm using %errorlevel% to catch the exit code, but in the case of the rd command it seems not to work:
C:\Users\edo\Desktop>rd testdir
Directory is not empty
C:\Users\edo\Desktop>echo %errorlevel%
0
Why? What do you suggest?
Wow, this is the 2nd case I've seen where ERRORLEVEL is not set properly! See File redirection in Windows and %errorlevel%.
The solution is the same as for detecting redirection failure. Use the || operator to take action upon failure.
rd testdir || echo The command failed!
The bizarre thing is, when you use the || operator, the ERRORLEVEL is then set properly to 145 if the folder was not empty, or 2 if the folder did not exist. So you don't even need to do anything. You could conditionally "execute" a remark, and the errorlevel will then be set properly.
rd testdir || rem
echo %errorlevel%
I thought the above gave a complete picture. But then a series of comments below demonstrated there are still potential problems when /RD /S is used.
If a file or subfolder under the parent folder is locked (at any level under parent) then RD /S /Q PARENT && echo removed || echo failed will print out an error message, but the && branch fires instead of the || branch. Very unfortunate. If the command fails because the parent folder itself is locked, then || will properly fire and set the ERRORLEVEL.
It is possible to detect failure in all cases by swapping stderr with stdout and piping the result to FINDSTR "^". If a match is found, then there must have been an error.
3>&2 2>&1 1>&3 rd /s test | findstr "^" && echo FAILED
The swap of stderr and stdout is important when /q is missing because it allows the "Are you sure (Y/N)?" prompt to be visible on stderr, separate from the error message on stdout.
rd does not set errorlevel to zero - it leaves errorlevel intact: f.e. if previous operation ends in positive errorlevel and rd finishes successfully it leaves errorlevel unchanged. Example: error levels of robocopy below 4 are warnings and not errors and can be ignored so the following code may end with error even when the directory was deleted successfully:
robocopy ...
if errorlevel 4 goto :error
rd somedir
if errorlevel 1 goto :error
Solution: ignore the error and check if the directory still exists after rd:
rd somedir
if exist somedir goto :error

Command script exit code not seen by same line && or ||?

Consider a command script named t.cmd that consists solely of these 2 lines:
#exit /b 123
#echo If you see this, THEN EXIT FAILED..
So, the script merely sets the exit code of the script's execution process to 123, but does not kill cmd.exe. The final echo confirms that exit actually causes an immediate return (its output should not appear).
Now execute this script, and then print out the %errorlevel%:
>t.cmd
>echo %errorlevel%
123
So far so good: everything behaves exactly as expected.
But now execute the above all on one line, using && for conditional execution:
>t.cmd && echo %errorlevel%
123
I do NOT expect this: if t.cmd really returns with a non-0 exit code, then it should stop everything after that && (i.e. the echo) from executing. The fact that we see it print means that it DID execute. What the heck is going on?
And if execute the above all on one line, using || for conditional execution:
>t.cmd || echo %errorlevel%
>
This behavior is also the opposite of what I expect (altho it is consistent with the && behavior above).
Note that this weird behavior is ONLY true for bat files, but not for "raw commands".
Proof: consider the following command line interactions where instead of calling t.cmd, I try to execute the bogus command abcdef:
>abcdef
'abcdef' is not recognized as an internal or external command,
operable program or batch file.
>echo %errorlevel%
9009
>abcdef && echo %errorlevel%
'abcdef' is not recognized as an internal or external command,
operable program or batch file.
>abcdef || echo %errorlevel%
'abcdef' is not recognized as an internal or external command,
operable program or batch file.
9009
Here, && and || immediately see the exit code of the failed bogus command.
So why do cmd files behave differently?
A possibly related bug in cmd.exe has been observed in File redirection in Windows and %errorlevel%
Also, I am aware that ERRORLEVEL is not %ERRORLEVEL%
By the way, the code above was all executed on a Win 7 Pro 64 bit box. I have no idea how other versions of Windows behave.
With t.bat slightly modified as follows:
#exit /b 123%~1
#echo If you see this, THEN EXIT FAILED..
Think out next output:
==>t.bat 1
==>echo %errorlevel%
1231
==>t.bat 2&echo %errorlevel%
1231
==>echo %errorlevel%
1232
==>cmd /V /C t.bat 3^&echo !errorlevel!
1233
==>echo %errorlevel%
0
==>cmd /V /C t.bat 4^&echo !errorlevel!^&exit /B !errorlevel!
1234
==>echo %errorlevel%
1234
==>
Resources
(%~1 etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
Edit to enlighten EnableDelayedExpansion:
==>cmd /v
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.
==>t.bat 5&echo !errorlevel!
1235
==>echo %errorlevel%
1235
==>
Edit 2 to enlighten (or confuse?) && and ||. Save next code snippet as errlevels.cmd:
#ECHO ON >NUL
#SETLOCAL enableextensions enabledelayedexpansion
(call )
#echo ^(call ^) command clears errorlevel %errorlevel%
abcd /G>NUL 2>&1
#echo abcd /G: "'abcd' not recognized" errorlevel %errorlevel%
abcd /G>NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
#echo abcd /G: ^|^| changed errorlevel %errorlevel%
find /G >NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
#echo find /G: ^|^| unchanged errorlevel %errorlevel%
call t.cmd 333 && echo YES !errorlevel! || echo NO !errorlevel!
type t.cmd
t.cmd 222 && echo YES !errorlevel! || echo NO !errorlevel!
Output (from errlevels.cmd):
==>errlevels.cmd
==>(call )
(call ) command clears errorlevel 0
==>abcd /G 1>NUL 2>&1
abcd /G: "'abcd' not recognized" errorlevel 9009
==>abcd /G 1>NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
NO 1
abcd /G: || changed errorlevel 1
==>find /G 1>NUL 2>&1 && echo YES !errorlevel! || echo NO !errorlevel!
NO 2
find /G: || unchanged errorlevel 2
==>call t.cmd 333 && echo YES !errorlevel! || echo NO !errorlevel!
NO 333
==>type t.cmd
#exit /B %~1
==>t.cmd 222 && echo YES !errorlevel! || echo NO !errorlevel!
YES 222
==>
Note that
|| shows errorlevel 1 although 'abcd' not recognized error should be 9009 whilst
|| keeps errorlevel 2 unchanged for FIND: Invalid switch error.
|| branch evaluates in call t.cmd 333 whilst
&& branch evaluates in t.cmd 222.
On (call ) see DBenham's answer:
If you want to force the errorlevel to 0, then you can use this
totally non-intuitive, but very effective syntax: (call ). The space
after call is critical.
If you want to set the errorlevel to 1, you can use (call). It
is critical that there not be any space after call.
%errorlevel% is expanded when line is read. So it is 123 at the time the line was read so comes from the previous command not t.exe. && is executed only if the current errorlevel (from t command) is 0.
See setlocal /? and set /? for more info.
#JosefZ's response provides excellent coverage of the disparity between ERRORLEVEL and exit code with respect to command scripts.
Unfortunately, as he pointed out, the && and || operators will only work if you invoke your command script with the call command. In most cases, you'd prefer that users can just run your command script, without having to remember to prefix it with a call each time.
Typically, I want my scripts to set both the ERRORLEVEL and the exit code to indicate failure (in order to have my scripts behave the same as regular executables). I used to use exit /b <nonzero> to try to do this, but had the problem indicated above.
It turns out that the Windows command interpreter exits with the exit code of the last command executed. The actual exit code of the exit /b <nonzero> command is, ironically, 0 (since it successfully exited). It does set the ERRORLEVEL, but not the exit code. Thus, that command won't work. The solution to all this is to (1) use the cmd /c exit <nonzero> command, and (2) to have it execute as the last command in the script. Since the cmd command returns back to the script, where the next command is then executed, the only way to get it to be the last line executed is to have it be the last line of your script.
Thus, here's a solution to get everything to behave as the OP requested:
#echo off & setlocal
if "%1" equ "fail" (
echo -- Failure
goto fail
) else (
echo -- Success
exit /b 0
)
:fail
#REM // Exit with script a failure exit code.
cmd /c exit 37

FindStr isn't work correct

I made a piece of batch-code, and I thought this will work. What I'm thinking that this code is doing? I have some plugins and I want to test if the deploy correct. So I get the pluginlink from the plugins.txt. Then I get the plugin from SVN with the java sentence. I deploy the plugin and get the feedback in test1.txt. Then I do a findStr in that file and searchs for "BUILD SUCCESSFUL" if it is there I want to add the sentence Build Gelukt and if it fails I want to add Build Fout. But I get always the answer Build Gelukt, while as you can see in the image he sends back that the build is Failed.
Whats wrong with this piece of code?
for /f "tokens=* delims= " %%a in (plugins.txt) do (
echo %%a
cd "C:\dotCMS Automatic Install"
java -cp .;"C:\dotCMS Automatic Install\svnkit.jar" Test %%a
cd %dotcms_home%
call ant deploy-plugins > test1.txt
FindStr "SUCCESSFUL" test1.txt
if %ERRORLEVEL% ==1 (echo ^<tr BGCOLOR=\"#FFFFFF\"^>^<td^>%%a^</td^>^<td^>Build Fout^</td^>^</tr^> >> C:\dotCMSResults\goedje.html ) else (echo ^<tr BGCOLOR=\"#00FF00\"^>^<td^>%%a^</td^>^<td^>Build Gelukt^</td^>^</tr^> >> C:\dotCMSResults\goedje.html)
del test1.txt
rem call ant undeploy-plugins >> test.txt
)
Classic batch problem - you are setting your ERRORLEVEL and attempting to access it using %ERRORLEVEL% within the same DO() clause. %VAR% expansion happens at parse time, and the entire FOR ... DO() statement is parsed once, so you are seeing the value of ERRORLEVEL before the statement was executed. Obviously that won't work.
jeb alluded to the answer in his comment regarding disappearing quotes. Your problem will be fixed if you setlocal enableDelayedExpansion at the top, and then use !ERRORLEVEL! instead of %ERRORLEVEL%. Also, GregHNZ is correct in that the ERRORLEVEL test should occur immediately after your FINDSTR statement.
There are other ways to handle ERRORLEVEL within parentheses that don't require delayed expansion:
The following tests if ERRORLEVEL is greater than or equal 1
IF ERRORLEVEL 1 (...) ELSE (...)
And below conditionally executes commands based on the outcome of the prior command
FindStr "SUCCESSFUL" test1.txt && (
commands to execute if FindStr succeeded
) || (
commands to execute if prior command failed.
)
The %ErrorLevel% variable applies to the immediately previous command only.
So when you do this:
echo Errorlevel: %ERRORLEVEL%
With your current code, you are getting the error level of the CD command above
Try putting your if %ERRORLEVEL% ==1 line immediately after the FindStr command, and then do the del and the cd afterward. Obviously you'll need to put the full path to the html file in your echo statement.

What is the easiest way to reset ERRORLEVEL to zero?

I have a post-build event that runs some commands for a c# project. The last command would sometimes cause the ERRORLEVEL value not equals to zero and then the build fails.
I want to append an extra line of command to always set the ERRORLEVEL value to zero. What is the most convenient way to do that?
if you use exit /b 0 you can return an errorlevel 0 from within a child batch script without also exiting the parent.
Seems to do the trick:
ver > nul
Not everything works, and it is not clear why. For example, the following do not:
echo. > nul
cls > nul
In a pre- or post-build event, if the return code of an executable is greater than zero, and the call to the executable is not the last line of the pre- or post-build event, a quick way to mute it and avoid triggering a check for a non-zero errorlevel is to follow the failing line with a line that explicitly returns zero:
cmd /c "exit /b 0"
This is essentially a generic combination of the previously-mentioned solutions that will work with more than just the last line of a pre- or post-build event.
I personally use this:
cd .
Works even in unix shell.
But, this one might be a bit faster:
type nul>nul
Because Process Monitor shows QueryDirectory calls on cd .
PS:
cd . has another nice side effect in the unix shell. It does restore recreated working directory in the terminal if it has been opened before the erase.
Update:
And that is a bit more faster:
call;
Any windows command to find if a file is in use or not ? :https://www.dostips.com/forum/viewtopic.php?t=5542
I found that "exit 0" looks like a good way to deal with this problem.
Usage Example:
NET STOP UnderDevService /Y
exit 0
if the UnderDevService service is not started.
I use VERIFY or VERIFY > nul
If this is a snippet like "Post-build Event" etc., then you'll be fine appending:
(...) || ver > nul
at the end of the last command.
Alternatively
cmd /c "exit /b 0"
is very clean and non-idiomatic -- a reader who knows Windows shell will know what's going on, and what was your intent.
However, if you're in a batch script, you may want to use subrotines, which are a lightweight equivalent of the "child batch script" from akf's answer.
Have a subroutine:
:reset_error
exit /b 0
and then just
call :reset_error
wherever you need it.
Here's a complete example:
#echo off
rem *** main ***
call :raise_error
echo After :raise_error ERRORLEVEL = %ERRORLEVEL%
call :empty
echo After :empty ERRORLEVEL = %ERRORLEVEL%
call :reset_error
echo After :reset_error ERRORLEVEL = %ERRORLEVEL%
:: this is needed at the end of the main body of the script
goto:eof
rem *** subroutines ***
:empty
goto:eof
:raise_error
exit /b 1
:reset_error
exit /b 0
Which outputs:
After :raise_error ERRORLEVEL = 1
After :empty ERRORLEVEL = 1
After :reset_error ERRORLEVEL = 0
As you see - just calling and returning via goto:eof is not enough.
The following works in modern Windows (NT-based) systems that feature cmd.exe:
rem /* This clears `ErrorLevel`; the SPACE can actually be replaced by an
rem arbitrary sequence of SPACE, TAB, `,`, `;`, `=`, NBSP, VTAB, FF: */
(call )
The SPACE (or more precisely, an arbitrary sequence of one or more standard token separators, which are SPACE (code 0x20), TAB (code 0x09), ,, ;, =, NBSP (code 0xFF), VTAB (code 0x0B) and FF (code 0x0C)) is mandatory; if you omit it the ErrorLevel becomes set instead:
rem // This sets `ErrorLevel` to `1`:
(call)
There is a nice thread on DosTips.com where this technique came up.
Here is an alternative method, but which accesses the file system and might therefore be a bit slower:
dir > nul
rem /* Perhaps this is a little faster as a specific file is given rather
rem than just the current directory (`.` implicitly) like above: */
dir /B "%ComSpec%" > nul
Here are some other ways to reset the ErrorLevel state, which even work in MS-DOS (at least for version 6.22):
more < nul > nul
rem // The `> nul` part can be omitted in Windows but is needed in MS-DOS to avoid a line-break to be returned:
sort < nul > nul
The following methods work in MS-DOS only:
command /? > nul
fc nul nul > nul
keyb > nul
For the sake of completeness, this sets the ErrorLevel state to 1, valid for both Windows and MS-DOS:
< nul find ""
After reviewing all of the other answers, I decided to find which way was the most efficient for resetting the ERRORLEVEL. I made a quick script that recorded the time to execute each of these:
"cmd /c "exit /b 0"", "cd .", "ver", "type nul", and "VERIFY"
here is the output:
cmd /v:on /c set ^"q=^"^" & timeit.cmd "cmd /c ^!q^!exit /b 0^!q^!" "cd ." "ver" "type nul" "VERIFY"
cmd /c "exit /b 0" took 0:0:0.02 (0.02s total)
cd . took 0:0:0.00 (0.00s total)
Microsoft Windows [Version 10.0.18362.836]
ver took 0:0:0.00 (0.00s total)
type nul took 0:0:0.00 (0.00s total)
VERIFY is off.
VERIFY took 0:0:0.00 (0.00s total)
This took 0:0:0.06 (0.06s total)
after reviewing with Measure-Command {command} in Powershell, I found that it only really accepted cd . and cmd /c "exit /b 0" --am I doing something wrong?
I'd recommend either cd . or type nul since neither have a footprint on the output of the console, nor are they slow in any measure.
yeah I'm pretty bored
Add >nul after each command that's likely to fail - this seems to prevent the build from failing.
You can still check the result of the command by examining %errorlevel%.
For example:
findstr "foo" c:\temp.txt>nul & if %errorlevel% EQU 0 (echo found it) else (echo didn't find it)
I'm using this:
ping localhost -n 1 >null
I always just used;
set ERRORLEVEL=0
I've been using it for donkey's years.

Resources