File redirection in Windows and %errorlevel%
Asked Answered
P

2

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?

Phonic answered 27/4, 2012 at 16:3 Comment(0)
P
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
Plater answered 27/4, 2012 at 22:2 Comment(10)
@AndriyM - Are you sure ERRORLEVEL was 0 before you started the test? && REM does not "fix" ERRORLEVEL for me on either XP or Vista.Plater
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.Teplica
A really unexpected behaviour, but perhaps the errorlevel is set by teh exit from the command after setting by the redirectionsReims
@Reims - 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.Plater
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.Clubwoman
@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.Plater
@Plater 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.Clubwoman
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.Clubwoman
@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.Plater
@Plater 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.Clubwoman
S
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.

Stupidity answered 12/11, 2019 at 8:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.