Batch/cmd - subroutine does not "return" array via parameter
batch file call command with parameters
batch file function with parameters
batch file subroutine parameters
batch file goto not working
batch file with parameters example
go to in bat file
batch file break
In the following script I want to pass a string via variable and the variable name for an array which should contain substrings to a subroutine.
The subroutine puts substrings of the passed string into an array/list which then should get "returned" by setting it as the value of the 2. passed parameter.
@ECHO OFF SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION SET testString=Hello World REM Pass testString and substrings to subroutine CALL :get_substrings testString substrings REM For testing. Echo substrings. DOESN'T WORK. substrings is empty! FOR /L %%s IN (0,1,2) DO ( ECHO !substrings[%%s]! ) ENDLOCAL EXIT /B 0 :get_substrings SETLOCAL ENABLEDELAYEDEXPANSION SET "string=!%~1!" REM Alternative approach: Make a connection to %2 rightaway REM SET "substrings=!%~2!" REM Process string: Put substrings into indexed array. This works as expected! FOR /L %%s IN (0,1,2) DO ( SET substrings[%%s]=!string:~0,5! SET string=!string:~5! ) REM For testing. Echo the substrings. Works as expected! FOR /L %%s IN (0,1,2) DO ( ECHO !substrings[%%s]! ) REM For alternative approach REM ENDLOCAL REM End the local the set 2.param = substringsArray ENDLOCAL & SET %2=%substrings% EXIT /B 0
Processing the string by creating a array with substrings in the subroutine works as expected. But setting 2. parameters value and keeping the value after subroutine doesn't work...
Notes: The processing of the string is just a dummy. The real process is slightly different but the core with the substrings array is the same. The script is executable right away.
So, how can I get the value substrings back?
This does what you want:
@ECHO OFF SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION SET testString=Hello World REM Pass testString and substrings to subroutine CALL :get_substrings testString substrings REM For testing. Echo substrings. FOR /L %%s IN (0,1,2) DO ( ECHO !substrings[%%s]! ) ENDLOCAL EXIT /B 0 :get_substrings SETLOCAL ENABLEDELAYEDEXPANSION SET "string=!%~1!" REM Process string: Put substrings into indexed array. This works as expected! FOR /L %%s IN (0,1,2) DO ( SET substrings[%%s]=!string:~0,5! SET string=!string:~5! ) REM For testing. Echo the substrings. Works as expected! FOR /L %%s IN (0,1,2) DO ( ECHO !substrings[%%s]! ) REM End the local the set 2.param = substringsArray set SubEnviron=1 for /F "tokens=2* delims=[]=" %%a in ('set substrings[') do ( if defined SubEnviron ENDLOCAL set "%2[%%a]=%%b" ) EXIT /B 0
Using Batch File Subroutines, In other scripting languages such as VBScript, the end of the "main program" is unmistakable, but in the batch file language it is not. You must use Batch files are not structured programs; they are a sequence of instructions with some BASIC-like facility for GOTO and CALL. If you want to return from a CALL, you use EXIT command with /B argument (as "EXIT" alone will terminate the batch file).
I wasn't able to understand your counting of characters so here's how I'd probably do it:
@Echo Off SetLocal EnableDelayedExpansion Set "TestString=Hello World" For /F "Delims==" %%A In ('Set SubString[ 2^>Nul') Do Set "%%A=" Set "i=1" Set "SubString[%i%]=%TestString: ="&Set/A i+=1&Set "SubString[!i!]=%" Set SubString[ Pause
Example Output:
SubString[1]=Hello SubString[2]=World Press any key to continue . . .
For the purposes of testing you probably don't need the For
loop, its purpose is to ensure there are no existing variables whose name begins with SubString[
Edit
This uses three parameters:
- The string to cut
%string%
- A number of how long each substring should be
%chrnum%
- The substring parameter
%strvar%
@Echo Off SetLocal EnableDelayedExpansion Set "string=montuewedthufrisatsun" Set "chrnum=3" Set "strvar=substring" Set "i=1" Set "_=%string%" :Loop Set "!strvar![%i%]=!_:~,%chrnum%!" If "!_:~%chrnum%!"=="" GoTo Write Set "_=!_:~%chrnum%!" Set /A i+=1 GoTo Loop :Write Set !strvar![ 2>Nul Pause
Call - Windows CMD, Call one batch program from another, or call a subroutine. the parent batch program" it is true that the parent does not STOP, but it does PAUSE The CALL command will launch a new batch file context along with any specified parameters. does not return. In other words, the default mode for batch file invocation is chain.) In other words, the call command lets you invoke another batch file as a subroutine. The command line parameters are received by the other batch file as the usual numbered parameters %1, %2, etc. It's annoying having to put every subroutine inside its own
Yes, I fully understand that you are not going to change this code to PowerShell. But, it might be worth considering for the next time given how easy it is. get_substrings is a lambda.
PS C:\src\t\selarr> type .\lamb002.ps1 $teststring = 'hello cruel world' $get_substrings = { param($t) foreach ($s in $t.split()) { $s.Substring(0,4) } } $a = & $get_substrings $teststring $a.length $a[0] $a[1] $a[2] PS C:\src\t\selarr> .\lamb002.ps1 3 hell crue worl
GOSUB, If the label still is not found, the batch file is terminated with the error message "Label not found". You can define GOSUB variables by placing them after the label GOSUB can only be used in batch files. TCC allows subroutines in batch files. A subroutine must start with a label (a colon [:] followed by a label name) which appears on a line by itself, and cannot be included a command group. Case differences are ignored when matching labels. The subroutine must end with a RETURN statement.
Exit batch file from subroutine, @ECHO OFF SETLOCAL IF "%selfWrapped%"=="" ( REM this is necessary so that we can use "exit" to terminate the batch file, REM and all subroutines, but not The called batch file should always either return (by executing its last line, or by using the QUIT command), or it should terminate batch file processing with CANCEL. Do not restart or CALL the original batch file from within the called file as this may cause an infinite loop or a stack overflow.
Exiting a batch file without exiting the command shell -and- batch file , Prepare your party hats: Batch File Week is almost over. when you start playing with batch file subroutines. Okay, let's back does not return. Thus, when you call `exit /b`, that command sets the ERRORLEVEL and then the batch script exits with a code of 0 (because it successfully executed). Thus, the test command above may indeed set an ERRORLEVEL, but it will not return a failure exit code, such that the command `echo fail` will actually execute.
Batch files, In "real DOS", the GOTO command is used to skip part of a batch file: There is, of course, always a way to fake subroutines in batch files: Always terminate a label with a line feed, or ("true") DOS won't be able to find it. Batch Script - Functions. A function is a set of statements organized together to perform a specific task. In batch scripts, a similar approach is adopted to group logical statements together to form a function. Function Declaration − It tells the compiler about a function's name, return type, and parameters.
Comments
- The simplest way to do what you want (that is, that the array variables created in the subroutine could be accessed in the caller program) is eliminate
SETLOCAL / ENDLOCAL
from the subroutine and use%~2
insteadsubstrings
varname. So the real question here is: why you need to useSETLOCAL
in the subroutine? You can explicitly delete the not desired variables at subroutine end... - So the real question here is Yeah, you are right... Maybe its not really necessary. It worked here thats why I wanted to know why it isn't working in my case.
- Yes, it works in your example because it returns just one variable and an array in Batch is comprised of several variables... See my solution. I also suggest you to read this post about "arrays" in Batch.
- I have one question about the code. Why is it necessary that the delimiter is
"... delims=[]="
with an extra equal sign and not"... delims=[]"
? - The
set substrings[
command list values like this one:substrings[1]=Hello
. If you not include the equal sign in the delimiters then the assigned value would include it; that is, theset "%2[%%a]=%%b"
line would becomeset "substrings[1]==Hello"
. - I wasn't able to understand your counting of characters. That isn't important, just how I said: The processing of the string is just a dummy. The real process is slightly different but the core with the substrings array is the same.
- @goulashsoup , if you replace
Hello World
with your real string of substrings, what does the above code output? and is that what you intended it to do? - The
get_substrings
routine actually expects 3 parameters. 1. The string to cut. 2. A number of how long each substring should be 3. The substring parameter which should later be used in the main part. The goal of the subroutine is to cut a long message into substrings so they can be outputed in more then one line. Because this process allreadys works and is not part of the question I simplified theget_substrings
routine with a dummy process which also creates a substrings array just like my process. The goal of the question is the answer of how I get back the substrings array. - With the above comment it should be clear that substring doesn't mean word by word.
- @goulashsoup, I'd suggest you rewrite your question and code to make them both accurate and pertinent then. For instance if your question was I have the following,
@Echo Off
,Set string=montuewedthufrisatsun"
,Set chrnum=3
. I'd like to split%string%
into an array of variables, in the form%substring[#]%
, each value having the number of characters, determined by the%chrnum%
value. Example%substring[1]%=mon
,%substring[2]%=tue
,%substring[3]%=wed
,%substring[4]%=thu
,%substring[5]%=fri
,%substring[6]%=sat
and%substring[7]%=sun
. Would that not better explain things?