25

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?

aschipfl
  • 33,626
  • 12
  • 54
  • 99
lukuluku
  • 4,344
  • 3
  • 30
  • 35

2 Answers2

32

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
approxiblue
  • 6,982
  • 16
  • 51
  • 59
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • 1
    @AndriyM - Are you sure ERRORLEVEL was 0 before you started the test? `&& REM` does not "fix" ERRORLEVEL for me on either XP or Vista. – dbenham Apr 28 '12 at 18:08
  • You are right, it was the `1` set after the test with `||`. After your comment I re-checked and it was `0`. Thanks for correcting me. – Andriy M Apr 28 '12 at 18:34
  • A really unexpected behaviour, but perhaps the errorlevel is set by teh exit from the command after setting by the redirections – jeb Apr 30 '12 at 10:30
  • 1
    @jeb - I don't understand your theory. But I do agree this is very unexpected behavior. I have lots of code that handles redirection errors, but I've always used the `||` operator because I like the compactness. So I never uncovered this odd behavior until this question came up. – dbenham Apr 30 '12 at 11:58
  • I don't understand what `type nul > C:\does\not\exist\file.txt || rem` is supposed to do. It doesn't change `ERRORLEVEL` for me (Win Server 2012 R2) - it stays the same as set by the last command before redirection. – Ohad Schneider Apr 11 '16 at 16:00
  • @OhadSchneider - I can't speak for Win Server 2012, but on XP, Vista, Win7, and Win 10 `type nul >"bogusPath\test.txt" || rem` will set ERRORLEVEL to 1 if path "bogusPath\" does not exist. – dbenham Apr 11 '16 at 19:14
  • @dbenham looks like it's only one way though. If the redirection succeeds, the `ERRORLEVEL` stays unchanged (that is it still holds the value set by the last command before redirection) where I would expect it to be set to 0. – Ohad Schneider Apr 12 '16 at 10:38
  • OK I think I undesratnd what's going on. I was using `echo` rather than `type` e.g. `echo nul >"realpath.txt" || rem` and seeing as `echo` keeps `ERRORLEVEL` untouched I didn't see the change. – Ohad Schneider Apr 12 '16 at 10:42
  • @OhadSchneider - It doesn't matter what the command is - if the redirection fails, then the command is never executed. Successful redirection always leaves the ERRORLEVEL alone. Failed redirection only sets ERRORLEVEL to 1 if `||` is used. I can't explain it any better than that. – dbenham Apr 12 '16 at 11:41
  • @dbenham 10x. The confusing part was that `echo` never touches `ERRORLEVEL` so `echo nul >"realpath.txt" || rem` would leave `ERRORLEVEL` alone (because neither `echo` nor the redirection affect it) whereas `type nul>"realpath.txt" || rem` would set the `ERRORLEVEL` to 0 because `type` sets it to 0 and the redirection leaves it untouched. So to sum up: `cmd > file` will have the `ERRORLEVEL` of `cmd` if redirection was successful and 1 if it was not (regardless of the `ERRORLEVEL` set by `cmd`). In case `cmd` does not set `ERRORLEVEL`, a successful redirection will leave it unchanged as well. – Ohad Schneider Apr 12 '16 at 15:13
1

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.

Anton Shepelev
  • 922
  • 9
  • 19