To "Call" or "Not to Call" a batch file?

If from inside a bat file you called another batch file but still had a few remaining operations to complete, how can you make sure that the call to first bat file will after completion or error, will return to the file that called it in the first instance?

Example:

CD:\MyFolder\MyFiles
Mybatfile.bat


Copy afile toHere

or

CD:\MyFolder\MyFiles
CALL Mybatfile.bat


COPY afile toHere

What is the difference between using CALL or START or none of them at all? Would this have any impact on whether it would return for the results of the copy command or not?

101752 次浏览

call is necessary for .bat or .cmd files, else the control will not return to the caller.
For exe files it isn't required.

Start isn't the same as call, it creates a new cmd.exe instance, so it can run a called batch file asynchronosly

The `CALL' statement was introduced in MS-DOS 3.3

It is used to call other batch files within a batch file, without aborting the execution of the calling batch file, and using the same environment for both batch files.

So in your case the solution is to use CALL

As others have said, CALL is the normal way to call another bat file within a .bat and return to the caller.

However, all batch file processing will cease (control will not return to the caller) if the CALLed batch file has a fatal syntax error, or if the CALLed script terminates with EXIT without the /B option.

You can guarantee control will return to the caller (as long as the console window remains open of course) if you execute the 2nd script via the CMD command.

cmd /c "calledFile.bat"

But this has a limitation that the environment variables set by the called batch will not be preserved upon return.

I'm not aware of a good solution to guarantee return in all cases and preserve environment changes.

If you really need to preserve variables while using CMD, then you can have the "called" script write the variable changes to a temp file, and then have the caller read the temp file and re-establish the variables.

Okay, I actually didn't even really think about the fact that if you call a batch (regardless of the 'type', i.e. '.bat', or '.cmd') that it won't return if you don't use call.

I've been using call myself though for a different reason that I am actually pretty surprised that no one else has brought up. Maybe I missed it. MAYBE I'M THE ONLY ONE IN THE WORLD WHO KNOWS!! :O

Probably not, but I'm going to drop this knowledge off here because it's super useful.

If you use call you can use binary logic operators to decide how to proceed based on the ERRORLEVEL result. In fact, I always was flabbergasted on how && and || existed in DOS and COULDN'T be used this way. Well, that's why.

The easiest way to test this is to create a return.cmd with notepad, or from the command prompt like so:

c:\> type con >return.cmd

You will now notice the cursor goes down to the next line and hangs. Enter:

@exit /B %1

And then hit ENTER, and then CTRL-Z and that file will be created. Good! You may now feel free to try the following two examples:

call return.cmd 0 && echo Huzzah! A Complete Success! (Or cover up...)

call return.cmd 123 || echo Oops! Something happened. You can check ERRORLEVEL if you want the tinest amount of additional information possible.

So what? Well, run them again with the 0 and the 123 swapped and you should see that the messages DON'T print.

Maybe this multi-line example will make more sense. I use this all the time:

     call return.cmd 0 && @(
echo Batch says it completed successfully^^!
) || @(
echo Batch completed, but returned a 'falsey' value of sort.
call echo The specific value returned was: %ERRORLEVEL%
)

(Note the 'call' in the || section before the second 'echo'. I believe this is how people got around not having delayed expansion back in the day. If you DO have delayed expansion enabled (via. setlocal EnableDelayedExpansion inside a batch OR launch a command prompt with cmd /v:on then you can just do !ERRORLEVEL!.)

... This is where I have to apologize and say if you have if ERRORLEVEL trauma in your past you should stop reading. I get it. Trust me. I thought about paying someone on fiverr to remotely type this for me, but for completeness sake I'm just going to take one for the team and mention that you can also do the following to check errorlevel:

    if ERRORLEVEL 123 @echo QUICK! MOTHERS, COVER YOUR CHILDREN'S EYES! FINGERS ARE BEING UNDONE! :'(

If you've never typed that before then GOOD! You will live longer without having to read up why exactly you aren't getting the results you expect. Cruel is the word you're looking for, not 'quirky'.


The important part that I really want to get across however is that if you try this and DON'T use 'call' it will ALWAYS execute the 'true' branch. Try it for yourself!

If I'm missing something, or you know a better way to do this, please let me know. I love learning stuff like this!


Additional information I mentioned:

I have known for quite some time that you can put redirects BEFORE commands like so:

    >nul echo. This won't be displayed!

But I accidentally discovered the other day by being a dumdum that you can apparently also do:

    echo A B>file.txt C

And was REALLY surprised to find a file.txt which consisted of "A B C". It appears yo can place them ANYWHERE, even inside the command. I've never seen anyone do this, nor mention it, but I HAVE seen people mention that you can prefix a line with them.

Maybe it's a bug exclusive to Windows 10 or something. If you have another version and wanna try it out and let me know I'd be interested in what you find out.

Stay nerdy!