-1

I am playing around a bit with batch files and am having some problems. According to one website:

To exit a batch script file or exit a subroutine specify GOTO:eof this will transfer control to the end of the current batch file or the end of the current subroutine.

So, with that definition in mind, why won't certain portions of these two codes execute:

First One:

:Loop
echo I am in a loop.
GOTO:eof

Echo Hello

Goto Loop

echo Finish

pause

The only thing that prints is: I am in a loop. Nothing else prints.

Second One:

Echo Hello

Goto Loop

echo Finish

pause

:Loop
echo I am in a loop
GOTO:eof

echo Finish does not print. Why?

Also, can you briefly state what's the difference between Goto use and subroutines?

Thanks

UPDATE: While searching on Google for something else, I found this: Using CALL for labels in a batch script which I guess answers the question, but I would still like some elaboration please, such as

1) When to use GOTO and when to use Call? (which I suppose is related to my question above about differences between subroutines and GOTO)

2) For the first code, why does the sentence: "I am in a loop." print / get echoed, when it was never called upon / instructed to be executed?

2b) How can that portion be executed only when it's called upon?

UPDATE 2:

Well, how can I get something like this to work?

@echo off

    echo main line
    call :loop
    call :another
    call :loop
    echo main line again
    goto :eof

:loop
    echo inside the subroutine

:another
   echo hi!
Community
  • 1
  • 1
Rolo
  • 220
  • 2
  • 13
  • Why on earth do you write code that says "I am in a loop" when you are not?! And there is no benefit in writing Goto :eof when you are already at the end of the file – barlop Jun 07 '14 at 14:28
  • You need to stick lots of pauses in and figure out for yourself what is going on because in your comments you are making some really crazy assumptions about what is going on. Put pauses in, make predictions of what will happen, figure out what it is doing. You even include crazy assumptions in your code like calling a label loop, suggesting you assume it will loop. You really need to do some troubleshooting and breaking things down. You even ask why when you have a label and some code, that it runs the code. Write a simple program of label and code and you'd learn more. – barlop Jun 07 '14 at 14:53
  • -1 You just wrote that there was another line (some cmd /k) in your batch file that caused some of the strange behaviour that you claim you think you got but you didn't think it was important so you missed it out. At least you're honest, but this question is not well asked at all (or well thought through) – barlop Jun 07 '14 at 14:57

2 Answers2

1

The mission of a goto command is to change what the next line to execute will be by jumping to a existing label. The first line after the label will be the next line to execute. Independly of how many gotos are used in the code, if the execution reaches the end of the file (and this include goto :eof) or a exit /b is reached, the execution of the batch file ends.

To use a subroutine, it is necessary to use a call :label command. When this command is executed, a second line of execution is created. The first line (the calling code) is suspended until the second line (the subroutine) ends, and execution on first line will continue at the first command after the call.

When does a subrotine end its execution?

In other languages subrotines have a starting point and an ending point, some kind of syntax in its declaration that delimits which code belongs to the subroutine.

This is not the case in batch files. Subroutines only have a starting point, the label that is called, and execution does not end when another label is reached.

The subrotines end when its execution line ends and this happens when a exit /b is executed or the end of the batch file is reached. In both cases the execution line of the subroutine ends and the execution line of the calling code continues.

And, of course, in any scenario, if a exit command (without the /b switch) is executed, the current batch and the current console are closed.

For the questions

1) When to use goto and when to use call? It depends. They should be used when needed and this is determined by the problem to solve, the ideas on how to solve it and they way you code.

2) The labels in batch code do not define functions nor do they bound anything. They defined points in code where it is possible to jump or to call. But they no interfere in code execution, so, they are parsed, discarded if not needed in that moment (more or less), and the process continue on next line. Labels are not barriers that protect/block code after them. So in your code, the initial label is stepped over, and your first executable line is the echo command. After it, the goto:eof ends the execution of the batch file.

2b) If you don't want to execute the line unless invoked, ensure there is no way it can be reached unless called/jumped to.

@echo off
    echo main line
    call :loop
    echo main line again
    goto :eof

:loop
    echo inside the subroutine
MC ND
  • 69,615
  • 8
  • 84
  • 126
  • Thank you. O.k. So, you added the label to the bottom so it would work. I also see that you use `Call`. I added `:loop` to the top and commented out the `call` portion and the `echo` under `:loop` does print. So, it seems like adding it to the bottom is the solution. But what happens when one has more than one label? Please do take a look above at **Update 2**. Only the first two labels are called. The third one, which is the same first one again, doesn't execute. How can I get such a scenario to work? – Rolo Jun 07 '14 at 14:27
  • @Rolo, the code you have posted does not behave as you say. You have three calls and the three work. The output of this code is `main, subroutine, hi, hi, subroutine, hi, main` , that is main line, call to `:loop` that echoes `sub` and continues execution until end of file (echoing hi), call to `:another` that echoes hi, call to `:loop` that echoes `sub` and `hi` again, and new main. – MC ND Jun 07 '14 at 14:34
  • @Rolo, remember that a subroutine does not end on the next label, but when the end of file or `exit /b` is reached. Labels mark points where it is possible to jump or to be called. When a `goto` or `call` is used, they are searched and used, but the rest of the time there is no almost no difference if they are there or not. – MC ND Jun 07 '14 at 14:40
  • @Rolo What are you talking about when you say that in your "Update 2" "Only the first two labels are called" . There are only two labels + the implicit one of :eof Your first label is :loop and your second label is :another. I suppose you mean only the first 2 call statements are run, but that's not true. – barlop Jun 07 '14 at 14:46
  • You are right about the output. After `:another echo hi!` I had another line with `cmd /k` so the cmd box wouldn't close. I didn't put it here figuring it wasn't important. But now that I see what you said about `:loop` echoing the sub and continuing execution until the end of file (which is `:another`), I understand now why I was only getting the first three lines of the output that you mentioned. I thought it was the other `Call` being executed. – Rolo Jun 07 '14 at 14:53
  • @Rolo, no, the end of the file is not `:another`, the end of the file (and the point where `:eof` makes reference) is after the `echo hi!` – MC ND Jun 07 '14 at 15:05
  • @mc-nd What you said is what I meant. I am still thinking of `:another` and anything below it as being linked, which is why I said `:another` was the end of the file. Anyhow, I now understand why Hi! prints three times and why placing cmd /k after it causes Hi! to print only once as well as not continue with the other (third) call and the next line. I also now understand because of the other answer how to get the code in Update 2 to work the way I would want it to. Thanks. – Rolo Jun 07 '14 at 15:51
0

Goto goes there and doesn't come back. It's good if you want to end a program or do something and end a program.. It can be used for iteration too. And for running some code to be like a subroutine.

Call will go there and return. So it's like goto then do some code, then having another goto to go back to where it was.

If you want to do iteration, a Goto can do that too. Creating a loop.

But then the label has to be before the Goto

e.g.

:xyz
echo abc
goto :xyz

^^^ That is a loop.

If you want to run a batch file within a batch file, you usually want to and mean to use call, otherwise it won't continue after.

And you seem at one point to wonder why

:xyz
echo abc

why it echos abc. when you think there's nothing to instruct it to run that subroutine, well it's a label not necessarily used as a subroutine.

You could use it as a subroutine, but to do that you need to make sure it is never reached unless called.

goto :eof
:xyz
echo abc

^^^ that is a subroutine, which you could call.

Now when you want to run xyz like a subroutine, you would say call xyz obviously before the goto:eof

Regarding your latest update..

You want multiple subroutines

Your problem is that you don't have a goto :eof between your so-called subroutines so it runs one and then the following ones.

:abc

:def

:ghi

and you try to goto abc or call abc, then it is going to go through all of them..

you need to put a goto :eof at the end of each of what you want to be a subroutine.

you don't necessarily need a goto :eof at the very end because that is the end of the file anyway.

:abc

goto :eof

:def

goto :eof

:ghi

To apply that to your code

@echo off

    echo main line
    call :loop
    call :another
    call :loop
    echo main line again
    goto :eof

:loop
    echo inside the subroutine
    goto :eof
:another
   echo hi!

That gives the output that I think you want. Note the goto :eof I added to the loop label code.

ADDED EXAMPLE-

Earlier I didn't put a goto :eof before the abc label, that does demonstrate that a label alone does not make it a subroutine, but the goto before it if you want abc to be like a subroutine. I have done that in this example.

REM is a way of making a comment, you can try it from the cmd prompt.

REM YOU COULD PUT A LABEL HERE IT MAKES NO DIFFERENCE
echo main

goto :eof
:abc
goto :eof

:def

^^ in that program, none of those 'subroutines' run because I haven't called them, but one could put code in and call them or goto them. I didn't bother putting a goto :eof after :def because it is the end of the file, but one useful reason to do so is if you ever wanted to add another subroutine after :def e.g. :ghi then you'd want a goto :eof between them, as you'd want a goto :eof between any 'subroutines'. But you never need a goto :eof at the end of the file.

barlop
  • 12,887
  • 8
  • 80
  • 109
  • Very helpful. This was very illustrative. I was still a bit confused about the last label (i.e. `:ghi` or :`another`), and wondering if it still wouldn't execute without being called, but with some experimentation, I see that the `goto :eof` prevents that. Though eof is end of file, I was for some reason thinking it will go the last line of the file, but it's really after the last line or character, which is truly the end. In your abc, def, ghi example, to prevent `:abc` from executing again, I need to place a `goto :eof` above it, and all other code above that. – Rolo Jun 07 '14 at 15:35
  • @Rolo Right re eof being the end. But when you say "to prevent :abc from executing again, I need to place a goto :eof above it, and all other code above that." You're not entirely clear and sound somewhat wrong. Because the code following the abc label, in those examples is only executing once anyway and with or without an :eof at the top it could be run again.Putting a goto :eof above a label, is a useful design pattern, it will make sure that what follows that label only executes when called. But could execute many times if called many times. So, it would make it like a subroutine. – barlop Jun 07 '14 at 16:06
  • @Rolo I've added an example to make 'abc' like a subroutine. – barlop Jun 07 '14 at 16:11
  • Thanks. Regarding preventing `:abc` from executing again (after already being called), I meant if I had code like this: `@echo off echo Hello Call :abc call:ghi :abc echo I belong to abc goto :eof :def echo I belong to def goto :eof :ghi echo I belong to ghi` A `goto :eof` line before the label `:abc` prevents it from executing when not called. – Rolo Jun 07 '14 at 16:42
  • @Rolo Yes and even regardless of other code, a goto :eof before a label prevents the code after the label from executing when not called. – barlop Jun 07 '14 at 16:59