Michael
Michael

Reputation: 453

Subroutines in batch files

Given the following code:

@Echo off
ECHO Start
ECHO Calling SUB_A
CALL :SUB_A
ECHO Calling SUB_B
CALL :SUB_B

:SUB_A
    ECHO In SUB_A
    GOTO:EOF

:SUB_B
    ECHO In SUB_B
    GOTO:EOF

ECHO End

I expect this output:

Start
Calling SUB_A
In SUB_A
Calling SUB_B
In SUB_B
End

But I get this:

Start
Calling SUB_A
In SUB_A
Calling SUB_B
In SUB_B
In SUB_A

What am I doing wrong here?

Upvotes: 45

Views: 81978

Answers (5)

Joe
Joe

Reputation: 85

Do not use EXIT!

Example:

@rem a.bat
@echo off
echo a.bat
timeout /t 1

call b.bat

call c.bat
@rem b.bat
@echo off
echo b.bat
timeout /t 1

call :subB
rem call to c.bat will fail if using "exit" instead of "goto :end"
goto :end

:subB
echo subB
timeout /t 1
exit /b

:end
@rem c.bat
@echo off
echo c.bat
timeout /t 1

"exit" immediately aborts the call chain!

Upvotes: 0

Mark Manning
Mark Manning

Reputation: 1467

Just to stick my $0.02 worth in here:

I would have to say that DOS files (or DOS batch files) should always be written as :

[ Main Program ]

EXIT

[ All Subroutines ]

In this way - you can never fall into the subroutine section.

Also - always use REM statements before, during, and possibly after each section so you always know what a section is going to do.

And last - but not least - See if you can write a batch file so it becomes more generic so you can set it to one side and use it when you need to again.

Just my $0.02 worth of common sense you probably already know. :-)

OH! Sorry! Forgot to post my small sleeper subroutine I wrote. Here it is! :-)

REM
REM Calling the Sleeper subroutine
REM
call :sleeper
exit

REM
REM Sleeper subroutine
REM
REM qna = Questions and Answers
REM
REM Interestingly - you can NOT use a '>'
REM Because DOS uses it for redirection!
REM Instead - use a question mark (?)
REM
:sleeper
set /p qna=Press return to continue or 'q' to stop ?
if [%qna%] == [q] (
    echo Exiting....please wait.
    exit
    )

goto :eof

Upvotes: 4

aikeru
aikeru

Reputation: 3983

If you want to return from a CALL, you use EXIT command with /B argument (as "EXIT" alone will terminate the batch file).

For example:

CALL :SUB_ONE
CALL :SUB_TWO

GOTO :EOF

:SUB_ONE
ECHO Hello from one
EXIT /B

:SUB_TWO
ECHO Hello from two
EXIT /B

:EOF

Upvotes: 76

Edmund
Edmund

Reputation: 10809

The line CALL :SUB_B returns, the script proceeds to the next few lines:

:SUB_A           # no effect from this one
ECHO In SUB_A    # prints message

You need to insert a GOTO:EOF after the call if you want it to stop there.

Batch files are not structured programs; they are a sequence of instructions with some BASIC-like facility for GOTO and CALL.

Upvotes: 22

BoltBait
BoltBait

Reputation: 11489

After your line CALL :SUB_B the batch file falls through to SUB_A. If you don't want it to, you need to put a GOTO line there.

Upvotes: 6

Related Questions