What is the equivalent to $? in Windows? - windows

Does anybody know what is the equivalent to $? in Windows command line? Is there any?
EDIT: $? is the UNIX variable which holds the exit code of the last process

You want to check the value of %ERRORLEVEL%.

Windows Batch Files
%ERRORLEVEL% Returns the error code of
the most recently used command. A non
zero value usually indicates an error.
http://technet.microsoft.com/en-us/library/bb490954.aspx
Windows Powershell
$?
Contains True if last operation succeeded and False otherwise. And
$LASTEXITCODE
Contains the exit code of the last Win32 executable execution.
http://blogs.msdn.com/powershell/archive/2006/09/15/ErrorLevel-equivalent.aspx
Cygwin Bash Scripting
$? Expands to the exit status code of
the most recently executed foreground
program.
http://unix.sjcc.edu/cis157/BashParameters.htm

Sorry to dredge up an old thread, but it's worth noting that %ERRORLEVEL% doesn't get reset with every command. You can still test "positive" for errorlevel after several lines of subsequent--and successful--batch code.
You can reliably reset errorlevel to a clean status with ver. This example works with UnxUtils for a more Linux-ish directory listing. The reset might seem extraneous at the end, but not if I need to call this script from another.
:------------------------------------------------------------------------------
: ll.bat - batch doing its best to emulate UNIX
: Using UnxUtils when available, it's nearly unix.
:------------------------------------------------------------------------------
: ll.bat - long list: batch doing its best to emulate UNIX
: ------------------------------------
: zedmelon, designer, 2005 | freeware
:------------------------------------------------------------------------------
#echo off
setlocal
: use the UnxUtil ls.exe if it is in the path
ls.exe -laF %1 2>nul
if errorlevel 1 (
echo.
echo ----- ls, DOS-style, as no ls.exe was found in the path -----
echo.
dir /q %1
)
: reset errorlevel
ver>nul
endlocal
Feel free to use this. If you haven't seen UnxUtils, check 'em out.

#echo off
run_some_command
if errorlevel 2 goto this
if errorlevel 1 goto that
goto end
:this
echo This
goto end
:that
echo That
goto end
:end

%errorlevel%

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.

File redirection in Windows and %errorlevel%

Lets say we want to create an empty file in windows with the following command:
type nul > C:\does\not\exist\file.txt
the directory does not exist, so we get the error:
The system cannot find the path specified
If you print out the %errorlevel% the output is:
echo %errorlevel%
0
Yet the command was not successful!
I noticed, that windows does not set the %errorlevel% of the last command if you use redirection..
Is there a way around this?
You can use the following:
C:\>type nul > C:\does\not\exist\file.txt && echo ok || echo fail
The system cannot find the path specified.
fail
C:\>echo %errorlevel%
1
I always assumed the && and || operators used ERRORLEVEL, but apparently not.
Very curious that ERRORLEVEL is set after redirection error only if you use the || operator. I never would have guessed. Nor would I ever have bothered to test if not for your excellent question.
If all you want to do is set the ERRORLEVEL upon redirection failure, then of course you can simply do:
type nul > C:\does\not\exist\file.txt || rem
The command
type nul > C:\does\not\exist\file.txt
invoked with a non-existent path is terminated at redirection failure and type is not invoked at all. It therefore has no chance of setting ERRORLEVEL. The redirection, being performed by the shell, does not set ERRORLEVEL.
One solution is to pre-initalise ERRORLEVEL with a non-zero value. It will remain unchanged upon failure and will be reset to zero (by type) upon success:
#echo off
::pre-initialise ERRORLEVEL with a value of 1:
call :SETERROR 1
type NUL > NOSUCHDIR\test.txt
IF ERRORLEVEL 1 goto ERROR
echo All is well.
goto END
:ERROR
echo Error detected.
:END
goto :eof
:SETERROR
exit /b %1
The shorft form
type NUL > NOSUCHDIR\test.txt && goto OK || goto ERROR
works because it analyses exit code, which is not the same as error level:
An exit code can be detected directly with redirection operators (Success/Failure ignoring the ERRORLEVEL) this can often be more reliable than trusting the ERRORLEVEL, which may or may not have been set correctly.
Herbert Kleebauer explained this to me in the Usenet group alt.msdos.batch.
Update:
An anonymous user suggested an alternative solution based on the COPY command:
COPY NUL: C:\does\not\exist\file.txt
This command does set ERRORLEVEL, which may be analysed by the next command in the script. Very convenient, so I thank him for the proposed edit.

If not exists then exit + cmd

i try to make a loop in a .cmd file.
If test.txt is not exists then i will kill the cmd process.
#echo off
if not exists test.txt goto exit
But this code doesn't work and i don't know how to make a loop every 2 seconds.
Thanks for help.
The command is called exist, not exists:
if not exist test.txt goto :exit
echo file exists
:exit
About your loop:
I am not 100% sure, but I think there is no sleep or wait command in Windows. You can google for sleep to find some freeware. Another possibility is to use a ping:
ping localhost -n 3 >NUL
EDIT:
The Windows Server 2003 Resource Kit Tools contains a sleep.
See here for more information, too
If you need to wait some seconds use standard CHOICE command. This sample code check if file exist each two seconds. The loop ends if file exists:
#ECHO OFF
:CHECKANDWAITLABEL
IF EXIST myfile.txt GOTO ENDLABEL
choice /C YN /N /T 2 /D Y /M "waiting two seconds..."
GOTO CHECKANDWAITLABEL
:ENDLABEL
exit is a key word in DOS/Command Prompt - that's why goto exit
doesn't work.
Using if not exist "file name" exit dumps you out of that batch file.
That's fine if exiting the batch file is what you want.
If you want to execute some other instructions before you exit, change the label to something like :notfound then you can goto notfound
and execute some other instructions before you exit.
(this is just a clarification to one of the examples)
Using the following:
if not exist "file name" goto exit
Results in:
The system cannot find the batch label specified - exit
However using the same command without "goto" works, as follows:
if not exist "file name" exit

%~$PATH:1 expansion issue

So I recently stumbled on the (potentially) useful %~$PATH:1 expansion, however I seem to be unable to make it work correctly. I tried to use it to make a cheap Windows version of the which command, however the syntax seems to be defeating me. My batch file looks like this:
#echo off
echo %~$PATH:1
However when I run this with for example
which cmd
all I get as output of "ECHO is off.", which means according to the docs that the %~$PATH:1 didn't find "cmd". What am I doing wrong?
Checking for files with the extensions .exe, .cmd or .bat is not enough. The set of applicable extensions is defined in the environment variable PATHEXT.
Here is my version of a which command that honors the PATHEXT variable upon search:
#echo off
rem Windows equivalent of Unix which command
setlocal enabledelayedexpansion
if "%~1"=="" (
echo Usage: which cmdname
exit /b 1
)
call :findOnPath "%~1"
if not errorlevel 1 exit /b 0
for %%E in (%PATHEXT:;= %) do (
call :findOnPath "%~1%%E"
if not errorlevel 1 exit /b 0
)
echo "%~1" not found on PATH.
exit /b 1
:findOnPath
if not "%~$PATH:1" == "" (
echo "%~$PATH:1"
exit /b 0
)
exit /b 1
Shoot! I just figured it out! I need to use the full "cmd.exe" as a parameter instead of just "cmd". D'oh! ;] So, the complete which.cmd script looks like this:
#echo off
call :checkpath %1
call :checkpath %1.exe
call :checkpath %1.cmd
call :checkpath %1.bat
:checkpath
if "%~$PATH:1" NEQ "" echo %~$PATH:1
Yeah! Finally a which command on Windows! ;]
I have been using this one for a while, it also checks built-in commands

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