Starting batch with a particular goto command - batch-file

I want to know if it is possible to start a batch thin in a particular goto function from another batch?
thus not just starting another batch file but also have the "mother" batch select a particular goto option with in the "child"batch?

1.bat
call 2.bat /c goto :this
call 2.bat /c call :that
.
2.bat
if "%1"=="/c" shift & shift & %2 %3
goto :eof
:this
echo This!
goto :eof
:that
echo That!
goto :eof
EDIT: My original post was closest to correct. But I've corrected my mistake(s).
I double shift to remove %1 and %2 to the left, bringing any other variables passed to the %1 and %2 positions. I then execute %2 and %3 because the effect of the shifts won't take effect until the line is finished being executed / interpreted.

Just have the parent/mother batch file and pass a parameter to the child batch file.
mom.bat
#ECHO OFF
ECHO Here we go
CALL child.bat 3
PAUSE
child.bat
#ECHO OFF
IF "%1"=="1" Goto 1
IF "%1"=="2" Goto 2
IF "%1"=="3" Goto 3
EXIT
:1
ECHO 1!
PAUSE
EXIT
:2
ECHO 2!
PAUSE
EXIT
:3
ECHO 3!
PAUSE
EXIT
This example should echo 3! as the mother batch file passes the parameter 3 to the child batch file.

Yes, but it's a hack.
Normally you would do this with a bit of help from the called batch file.
main.bat
call second.bat :theFunction
*second.bat
goto %1
...
:theFunction
The hack uses a feature-bug, you only need the same label as in the second.bat.
And it only works if you start the second.bat without call
main.bat
call :theFunction
echo back in main
exit /b
:theFunction
second.bat
echo back in the func in main, this line will never reached
exit /b This line will also never reached
When the second.bat returns , it will return to the line after the call in main.bat

In the batch file that you are calling put this at the top
if not %1=="" goto :%1
In the batch file you are using to call it put
call b.bat labelname
Obviously this is limited depending on what you are trying to do but the basic functionality works.

Related

batch file loops once again at the end with nothing in variable

having an issue with a batch file which i would use in front of vagrant provisioning (merging files into an install-script to perform installation depending on user input) which looks like this:
#echo off
copy %CD%\Vagrantfile_base %CD%\Vagrantfile
echo Vagrant Provisionierung
echo 1 - nodejs
echo 2 - Nginx
echo 3 - Qt
echo 4 - Git
echo 5 - gcc
echo a - Alle vorgenannte Software
set /p choice=Mittels Zahlen durch Komma getrennt angeben, was installiert werden soll (Bspw. 1,2,3):
for %%i in (%choice%) do (
if "%%i"=="1" call :nodejs_install
if "%%i"=="2" call :nginx_install
if "%%i"=="3" call :qt_install
if "%%i"=="4" call :git_install
if "%%i"=="5" call :gcc_install
if "%%i"=="a" call :all_install
)
:nodejs_install
copy /b %CD%\software.sh+%CD%\software\nodejs_install.sh software.sh
PAUSE
goto :EOF
:nginx_install
copy /b %CD%\software.sh+%CD%\software\nginx_install.sh software.sh
PAUSE
goto :EOF
:qt_install
copy /b %CD%\software.sh+%CD%\software\qt_install.sh software.sh
PAUSE
goto :EOF
:git_install
copy /b %CD%\software.sh+%CD%\software\git_install.sh software.sh
PAUSE
goto :EOF
:gcc_install
copy /b %CD%\software.sh+%CD%\software\gcc_install.sh software.sh
PAUSE
goto :EOF
:all_install
call :nodejs_install
call :nginx_install
call :qt_install
call :git_install
call :gcc_install
PAUSE
goto :EOF
PAUSE
So when i execute the script it always calls the nodejs_install at the end even if i didnt choose it and i dunno why.
When i add an echo for the i it is empty shown.
Searching for very long but didnt found anything.
Maybe someone has an answer and/or fix for this?
Batch does not have true subroutines; if you do not protect the entry point of a subroutine with a GOTO to get around it, it will "fall through" into the routine. You need a GOTO :EOF after the ) and before the :nodejs_install.

I am trying to make a batch that call two subbatchs depending on a response. It does not working properly

This is the code, sorry is my first question
[I think you'll get better responses by copying in the code here instead of showing a picture of it]
Your call to the subroutine is
Call :TestCom2
and the subroutine starts with a label
:TestCom2
and ends with
GoTo :EOF
Denis
Here's an example of a batch file containing a subroutine.
prompt $g
set fred="a b c d e f g"
call :TestSub1 %fred%
call :TestSub2 %fred%
GoTo EndBatch
:TestSub1
echo %1
Pause in TestSub1
GoTo :eof
:TestSub2
echo %~1
Pause in TestSub2
GoTo :eof
:EndBatch
Pause at EndBatch

How to go to label in called batch file

My code is like this in one.bat:
#echo off
echo hi
call example.bat
:label
echo hello
pause
My code is like this in example.bat:
#echo off
echo hi!
call one.bat
I want it to goto the label once one.bat is called. How do I do this?
If you want to return to the line below where you called example.bat (place where you currently have the label) , you don't need the label. Use exit /b at end of example.bat.
#echo off
echo hi!
exit /b
:: Takes you back to the batch file at the spot you left it
If you really do want to go to a label in one.bat, put goto %1 at the top of one.bat (right under #echo off) and pass a variable with the name of the label when you do the call. Like this:
#echo off
echo hi!
set gotoPlace=label
call one.bat %gotoPlace%
Calling One.bat starts it over again, but the variable you are passing to One.bat (%gotoplace%) replaces the %1 that you put at the top of the file, so "goto %1" now equals "goto label".
Edit: %1 used this way does what you want in your very simple batch file, but typically you wouldn't want goto %1 at the top of a bat. The beginning of this page tells more about passing items from one batch file to another.
The trouble with contrived code is that the answer to the question may not be what you are looking for :)
#echo off
echo hi
echo hi!
start "" "%comspec%" /c one.bat
echo hello
pause

Accessing Batch Functions in another batch file

Alright, so lets say we have a file called "lib.cmd" it contains
#echo off
GOTO:EXIT
:FUNCTION
echo something
GOTO:EOF
:EXIT
exit /b
Then we have a file called "init.cmd" it contains
#echo off
call lib.cmd
Is there anyway to access :FUNCTION inside of init.cmd? Like how bash uses "source" too run another bash file into the same process.
Change your lib.cmd to look like this;
#echo off
call:%~1
goto exit
:function
echo something
goto:eof
:exit
exit /b
Then the first argument passed to the batch file (%~1) will identify as the function you want to call, so it will be called with call:%~1, and now you can call it in init.cmd in this way:
call lib.cmd function
#echo off
(
rem Switch the context to the library file
ren init.cmd main.cmd
ren lib.cmd init.cmd
rem From this line on, you may call any function in lib.cmd,
rem but NOT in original init.cmd:
call :FUNCTION
rem Switch the context back to original file
ren init.cmd lib.cmd
ren main.cmd init.cmd
)
For further details, see How to package all my functions in a batch file as a seperate file?
The following takes #npocmaka solution and add support for calling functions in with arguments. Thanks #jeb for improvements. Let's save the following as lib.cmd:
#echo off
shift & goto :%~1
:foo
set arg1=%~1
set arg2=%~2
echo|set /p=%arg1%
echo %arg2%
exit /b 0
You can test it with:
call lib.cmd foo "Hello World" !
And it will print Hello World!.

How can I exit a batch file from within a function?

I have a simple function written to check for directories:
:direxist
if not exist %~1 (
echo %~1 could not be found, check to make sure your location is correct.
goto:end
) else (
echo %~1 is a real directory
goto:eof
)
:end is written as
:end
endlocal
I don't understand why the program would not stop after goto:end has been called. I have another function that uses the same method to stop the program and it work fine.
:PRINT_USAGE
echo Usage:
echo ------
echo <file usage information>
goto:end
In this instance, the program is stopped after calling :end; why would this not work in :direxist? Thank you for your help!
I suppose you are mixing call and goto statements here.
A label in a batch file can be used with a call or a goto, but the behaviour is different.
If you call such a function it will return when the function reached the end of the file or an explicit exit /b or goto :eof (like your goto :end).
Therefore you can't cancel your batch if you use a label as a function.
However, goto to a label, will not return to the caller.
Using a synatx error:
But there is also a way to exit the batch from a function.
You can create a syntax error, this forces the batch to stop.
But it has the side effect, that the local (setlocal) variables will not be removed.
#echo off
call :label hello
call :label stop
echo Never returns
exit /b
:label
echo %1
if "%1"=="stop" goto :halt
exit /b
:halt
call :haltHelper 2> nul
:haltHelper
()
exit /b
Using CTRL-C:
Creating an errorcode similar to the CTRL-C errorcode stops also the batch processing.
After the exit, the setlocal state is clean!
See #dbenham's answer Exit batch script from inside a function
Using advanced exception handling:
This is the most powerful solutions, as it's able to remove an arbitrary amount of stack levels, it can be used to exit only the current batch file and also to show the stack trace.
It uses the fact, that (goto), without arguments, removes one element from the stack.
See Does Windows batch support exception handling?
jeb's solution works great. But it may not be appropriate in all circumstances. It has 2 potential drawbacks:
1) The syntax error will halt all batch processing. So if a batch script called your script, and your script is halted with the syntax error, then control is not returned to the caller. That might be bad.
2) Normally there is an implicit ENDLOCAL for every SETLOCAL when batch processing terminates. But the fatal syntax error terminates batch processing without the implicit ENDLOCAL! This can have nasty consequences :-( See my DosTips post SETLOCAL continues after batch termination! for more information.
Update 2015-03-20 See https://stackoverflow.com/a/25474648/1012053 for a clean way to immediately terminate all batch processing.
The other way to halt a batch file within a function is to use the EXIT command, which will exit the command shell entirely. But a little creative use of CMD can make it useful for solving the problem.
#echo off
if "%~1" equ "_GO_" goto :main
cmd /c ^""%~f0" _GO_ %*^"
exit /b
:main
call :label hello
call :label stop
echo Never returns
exit /b
:label
echo %1
if "%1"=="stop" exit
exit /b
I've got both my version named "daveExit.bat" and jeb's version named "jebExit.bat" on my PC.
I then test them using this batch script
#echo off
echo before calling %1
call %1
echo returned from %1
And here are the results
>test jebExit
before calling jebExit
hello
stop
>test daveExit
before calling daveExit
hello
stop
returned from daveExit
>
One potential disadvantage of the EXIT solution is that changes to the environment are not preserved. That can be partially solved by writing the environent to a temporary file before exiting, and then reading it back in.
#echo off
if "%~1" equ "_GO_" goto :main
cmd /c ^""%~f0" _GO_ %*^"
for /f "eol== delims=" %%A in (env.tmp) do set %%A
del env.tmp
exit /b
:main
call :label hello
set junk=saved
call :label stop
echo Never returns
exit /b
:label
echo %1
if "%1"=="stop" goto :saveEnvAndExit
exit /b
:saveEnvAndExit
set >env.tmp
exit
But variables with newline character (0x0A) in the value will not be preserved properly.
If you use exit /b X to exit from the function then it will set ERRORLEVEL to the value of X. You can then use the || conditional processing symbol to execute a command if ERRORLEVEL is non zero.
#echo off
setlocal
call :myfunction PASS || goto :eof
call :myfunction FAIL || goto :eof
echo Execution never gets here
goto :eof
:myfunction
if "%1"=="FAIL" (
echo myfunction: got a FAIL. Will exit.
exit /b 1
)
echo myfunction: Everything is good.
exit /b 0
Output from this script is:
myfunction: Everything is good.
myfunction: got a FAIL. Will exit.
Here's my solution that will support nested routines if all are checked for errorlevel
I add the test for errolevel at all my calls (internal or external)
#echo off
call :error message&if errorlevel 1 exit /b %errorlevel%<
#echo continuing
exit /b 0
:error
#echo in %0
#echo message: %1
set yes=
set /p yes=[no]^|yes to continue
if /i "%yes%" == "yes" exit /b 0
exit /b 1

Resources