%errorlevel% expansion within subroutine

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
treintje
Posts: 6
Joined: 14 Oct 2016 16:00

%errorlevel% expansion within subroutine

#1 Post by treintje » 14 Oct 2016 18:40

I'm trying to check if md is executed successfully from within a subroutine. The problem is that %errorlevel% will always be 0, even if md has failed to create a directory. It seems that %errorlevel% is expanded before md is executed. This behaviour of %errorlevel% only seems to occur when I try to expand it from within a subroutine.

Code: Select all

@echo off
setlocal

call :MakeDir "treintje"
exit /b

:MakeDir ( sDirName[in] ) {
  if not exist "%~1\*" (
    md "%~1" 2> nul
    if %errorlevel% neq 0 ( :: will always expand to 0
      exit /b
    )
  )
  echo Hi there 1> "%~1\%~1.txt"
  exit /b
}
----------------------------------------
Creates a directory and a text file: %cd%\treintje\treintje.txt
Containing the text: Hi there

I don't understand why the expansion of %errorlevel% works that way. In the following code str seems to be expanded after the subroutine getstr is called. From my limited understanding, this seems to contradict the way how %errorlevel% is expanded in the first code.

Code: Select all

@echo off
setlocal

call :func
exit /b

:func
call :getstr str
set "str=%str%, world"
echo %str%
exit /b

:getstr
set /p %1=
exit /b
----------------------------------------
C:\Users\treintje\Desktop>test.bat
Hello
Hello, world

I know that I could solve the problem by using the || redirection operator to check the result of md or by using delayed expansion and use !errorlevel! instead. Or even adding an extra if exist check.

Code: Select all

:MakeDir ( sDirName[in] ) {
  if not exist "%~1\*" (
    md "%~1" 2> nul || exit /b
  )
  echo Hi there 1> "%~1\%~1.txt"
  exit /b
}

Unfortunately, this does not help me to understand how exactly %errorlevel% is expanded from within a subroutine and why it always expands to 0. I'm curious to know if there is a neat way to check the result of md while using the original %errorlevel% checking method and not to result to alternative solutions mentioned previously.

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: %errorlevel% expansion within subroutine

#2 Post by Squashman » 14 Oct 2016 21:04

You seem to know about delayed expansion so I am not sure what you do not understand? You are inside a code block. All variables are expanded before the commands are executed.

thefeduke
Posts: 211
Joined: 05 Apr 2015 13:06
Location: MA South Shore, USA

Re: %errorlevel% expansion within subroutine

#3 Post by thefeduke » 14 Oct 2016 23:13

Perhaps the behavior is more related to being within an IF statement than being in a subroutine.

John A.

treintje
Posts: 6
Joined: 14 Oct 2016 16:00

Re: %errorlevel% expansion within subroutine

#4 Post by treintje » 15 Oct 2016 05:25

It seems I have completely overlooked the fact that %errorlevel% was being expanded within the block of an IF statement. I decided to drop the initial directory existence check in the subroutine since it didn't provide any benefits in this particular case. Though, if the directory existence check was a necessity, I think I would have gone with the double pipe solution mentioned in my original post.

Code: Select all

:MakeDir ( sDirName[in] ) {
  md "%~1" 2> nul
  if %errorlevel% neq 0 (
    exit /b
  )
  echo Hi there 1> "%~1\%~1.txt"
  exit /b
}

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: %errorlevel% expansion within subroutine

#5 Post by foxidrive » 15 Oct 2016 06:35

treintje wrote:It seems I have completely overlooked the fact that %errorlevel% was being expanded within the block of an IF statement.


At this point it would have been a good time to acknowledge the help you were given and say thank you.

treintje
Posts: 6
Joined: 14 Oct 2016 16:00

Re: %errorlevel% expansion within subroutine

#6 Post by treintje » 15 Oct 2016 06:50

Okay, I guess I have overlooked things again :D. The directory existence check is necessary because the file has to be created even if the directory already exists, which was not the case in my previous code.

The reason I need to know whether md succeeded is because the subroutine has to abort operation if there already exists a file which has the same name as the directory I'm trying to create but without an extension.

Another solution is by checking the directory existence after md has failed. I do not like this method because it doesn't seem to be very logical.

Code: Select all

:MakeDir ( sDirName[in] ) {
  md "%~1" 2> nul
  if %errorlevel% neq 0 (
    if not exist "%~1\*" (
      exit /b
    )
  )
  echo Hi there 1> "%~1\%~1.txt"
  exit /b
}


So I guess I will have to stick to the double pipe solution.

Code: Select all

:MakeDir ( sDirName[in] ) {
  if not exist "%~1\*" (
    md "%~1" 2> nul || (
      :: this way implies more obviously that an actual check is going on and it allows for easier adaptation
      exit /b
    )
  )
  echo Hi there 1> "%~1\%~1.txt"
  exit /b
}

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: %errorlevel% expansion within subroutine

#7 Post by foxidrive » 20 Oct 2016 02:28

treintje wrote:Okay, I guess I have overlooked things again :D. The directory existence check is necessary because the file has to be created even if the directory already exists, which was not the case in my previous code.

The reason I need to know whether md succeeded is because the subroutine has to abort operation if there already exists a file which has the same name as the directory I'm trying to create but without an extension.


If you ever spend time helping people with programming support then you will finally realise the stupidity in not discussing the actual issue that you are getting frustrated with.

Your solution is to use an if exist check and branch on the result of that.

There are techniques to define if it is a folder in the if exist check, and you can then do what it is that you need to do.

Post Reply