Return value from a cmd function - batch-file

I have a batch function and I need to return a value from it. Following is the script:
#echo off
call :Mode mode1
echo mode is %mode1%
:Mode
setlocal enabledelayedexpansion
set count=0
for /f "tokens=*" %%x in (map.txt) do (
set /a count+=1
set var[!count!]=%%x
)
for /f "tokens=2 delims=: " %%A in ("%var[2]%") Do (
set mode=OPEN
)
IF %mode%==OPEN (
echo coming into open
set %1=OPEN
echo %mode1%
) ELSE (
echo coming into shorted
set %1=SHORTED
echo %mode1%
)
EXIT /B 0
echo mode is %mode1% doesn't print anything. Any help? I've hardcoded set mode=OPEN for testing purposes.

Each exit, exit /b or goto :eof implicitly does an endlocal, so you need a trick for your variable %1 to survive an endlocal. endlocal & set ... & goto :eof does the trick because the whole line gets parsed in one go:
#echo off
call :Mode mode1
echo mode is %mode1%
goto :eof
:Mode
setlocal enabledelayedexpansion
set "mode=OPEN"
IF "%mode%" == "OPEN" (
echo coming into open
endlocal&set "%1=OPEN"&goto :eof
) ELSE (
echo coming into shorted
endlocal&set "%1=SHORTED"&goto :eof
)
For the same reason, echo %mode1% in your subroutine does not print the variable.
Note: I changed set and if syntax to recommended quoted syntax.

Related

how to random array without duplicate using batch

Im using this batch for random test1-test3 without duplicate but not working
#echo off
setlocal EnableExtensions
setlocal EnableDelayedExpansion
set /A "RND_TOTAL=3, FLAG_DUP=0"
set /A "RND_MIN=1, RND_MAX=3, RND_INTER=1"
for /L %%I in (1,1,%RND_TOTAL%) do (
call :SUB %%I
SET /A R=!RND_NUM[%%I]!
SET LINE[1]=TEST1
SET LINE[2]=TEST2
SET LINE[3]=TEST2
echo !LINE[%R%]!
pause
)
endlocal
exit /B
:SUB
set /A "RND_COUNT=%1-1"
:LOOP
set /A "RND_NUM[%1]=!RANDOM!%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN"
if %FLAG_DUP% EQU 0 (
for /L %%I in (1,1,%RND_COUNT%) do (
if !RND_NUM[%1]! EQU !RND_NUM[%%I]! (
goto :LOOP
)
)
)
exit /B
I get the following output:
echo off
echo off
echo off

Variable name stored in delayed variable - Batch

I have:
setlocal EnableDelayedExpansion
var inLoopVar=hey
var first=!inLoopVar!
echo %!first!%
This outputs ECHO OFF because %!first!% is returned as empty.
How can I print "Hey"
Updated and Clarified:
Here is my full code with comment of what i am trying to do
#ECHO OFF
setlocal EnableDelayedExpansion
set RESULT=TRUE
set INPUT[0]=+NAME=RESULT; VARB=Second; VARC=Second; VARD=Second; VARE=Second; VARF=Second; VARG=Second;
set length=1
set i=0
:loop
if %i% equ %length% goto :eof
for /f "usebackq delims=+ tokens=2" %%j in (`set INPUT[%i%]`) do (
set y=%%j
FOR /f "tokens=1-7 delims=; " %%a IN ("!y!") DO (
set aaa=%%a
set testVar=!aaa:~5!
REM basically testVar resolves to RESULT
echo !!testVar!!
REM Above echo prints "RESULT"
echo %!!testVar!!%
REM Above echo prints "ECHO is off."
)
)
set /a i=%i%+1
goto loop
Instead of ECHO is off. i am trying to output TRUE
#ECHO OFF
setlocal EnableDelayedExpansion
set RESULT=TRUE
set INPUT[0]=+NAME=RESULT; VARB=Second; VARC=Second; VARD=Second; VARE=Second; VARF=Second; VARG=Second;
set length=1
set i=0
:loop
if %i% equ %length% goto :eof
for /f "usebackq delims=+ tokens=2" %%j in (`set INPUT[%i%]`) do (
CALL :sub %%j
)
set /a i=%i%+1
goto loop
GOTO :EOF
:sub
SET "namepart="
FOR %%a IN (%*) DO IF DEFINED namepart (
SET "Valuepart=!%%a!"
ECHO !namepart! is !valuepart!
SET "namepart="
) ELSE (
SET "namepart=%%a"
)
GOTO :eof
It would help if you would explain what you intend to do rather than set up an inquest to determine what you want to do by examining how you have failed to do whatever it is.

Multiplying error: * was unexpected at this time

I recently got a problem. I am making a game module in batch and I got a strange error:
Multiplying error "*!Map_PlayerLengthX! was unexpected at this time"
This is the whole code:
#echo off
setlocal enabledelayedexpansion
pause >nul
cls
call :Map_DefinePlayer 4 2 loloolol
echo %Px1y1%%Px2y1%%Px3y1%%Px4y1%
echo %Px1y2%%Px2y2%%Px3y2%%Px4y2%
pause >nul
:::::::::::::::::::::::::::
:: Map v0.10 By KKZiomek ::
:::::::::::::::::::::::::::
:Map_Init
set Map_Running=1
goto :eof
:Map_Load
if !Map_Running!==0 goto :eof
set Map_Load_FileToLoad=%~1
set Map_Load_BorderX=%~2
set Map_Load_BorderY=%~3
set Map_Load_BChar=%~4
set Map_Load_LineTotal=0
for /f "tokens=* delims= usebackq" %%l in (!Map_Load_FileToLoad!) do (
set /a Map_Load_LineTotal+=1
set Map_Line!Map_Load_LineTotal!=%%l
)
:Map_Load_ApplyCoords
for /l %%g in (1,1,!Map_Load_LineTotal!) do (
call :Map_Load_StrLen Map_Line%%g Map_Line%%g_Len
set /a Map_Load_ApplyCoords_DecidedLen+=!Map_Line%%g_Len!
)
set /a Map_Load_ApplyCoords_DecidedLen/=!Map_Load_LineTotal!
for /l %%y in (1,1,!Map_Load_LineTotal!) do (
for /l %%x in (1,1,!Map_Load_ApplyCoords_DecidedLen!) do (
set x%%xy%%y=!Map_Line%%y:~%%x,1!
)
)
goto :eof
:Map_Load_StrLen
setlocal disabledelayedexpansion
set Map_Load_StrLen_Len=0
if defined %~1 for /f "delims=:" %%n in (
'"(cmd /v:on /c echo(!%~1!&echo()|findstr /o ^^"'
) do set /a "Map_Load_StrLen_Len=%%n-3"
endlocal & if "%~2" neq "" (set %~2=%Map_Load_StrLen_Len%) else echo %Map_Load_StrLen_Len%
exit /b
:Map_Display
cls
for /l %%y in (1,1,!Map_Load_LineTotal!) do (
set Map_Display_Line%%y=
for /l %%x in (1,1,!Map_Load_ApplyCoords_DecidedLen!) do (
set Map_Display_Line%%y=!Map_Display_Line%%y!!x%%xy%%y!
)
)
for /l %%z in (1,1,!Map_Load_LineTotal!) do (
echo !Map_Display_Line%%z!
)
goto :eof
:Map_ReloadPos
set XPos=%~1
set YPos=%~2
set x!XPos!y!YPos!=!Map_Line%YPos%:~%XPos%,1!
goto :eof
:Map_DefinePlayer
set Map_PlayerLengthX=%~1
set Map_PlayerWidthY=%~2
set Map_DefinePlayer_Scheme=%~3
set /a Map_DefinePlayer_Modifier=!Map_PlayerLengthX!-1
for /l %%p in (1,1,!Map_PlayerWidthY!) do (
for /l %%q in (0,1,!Map_DefinePlayer_Modifier!) do (
set /a localq=%%q+1
set /a modq=%%q+((%%p-1)*!Map_PlayerLengthX!)
set Px%localq%y%%p=!Map_DefinePlayer_Scheme:~%modq%,1!
)
)
:::::::::::::::::::::::::::
:::::::::::::::::::::::::::
:::::::::::::::::::::::::::
I get the error in the function :Map_DefinePlayer. I think it's mainly in this line: set /a modq=%%q+((%%p-1)*!Map_PlayerLengthX!)
Every function works fine instead of this function because of this weird multiplying error. I tried enbling delayed expansion again, changing !Map_PlayerLengthX! into %Map_PlayerLengthX% but then it only changed the error in *4 was unexpected at this time
Anyone has an idea what causes this and how to fix it?
try with :
set /a "modq=%%q+((%%p-1)*!Map_PlayerLengthX!)"
the brackets in the expression are taken as closing brackets for the FOR loop

Batch - for /f loops running SET commands

This is my code:
:LevelSave
cls & echo.Choose a save file: & echo.
if exist savedata.txt (
for /f "tokens=*" %%P in ('type savedata.txt') do (
%%P
set /a q=q+1
echo. [!q!] !savename! - !lastcd!
set r=!r!!q!
)
)
This is the contents of savedata.txt
set savename=save1 && set lastcd=start\Continue on path
But when run, it outputs this:
Choose a save file:
save1 && set lastcd=start\Continue on path - save1
even when I remove the echo.
I've tried using different arrangements of quotes in the savedata.txt, though I think the problem is actually somewhere in the for command. Do you know what I'm doing wrong?
Just put a call before the 2 set in your savedata.txt
savedata.txt :
call set savename=save1 && call set lastcd=start\Continue on path
Here is a workaround:
savedata.txt
save1|start\Continue on path
save2|end\fallen into the pit
code
#echo off
setlocal enabledelayedexpansion
:LevelSave
cls & echo.Choose a save file: & echo.
if exist savedata.txt (
for /f "tokens=1,* delims=|" %%P in ('type savedata.txt') do (
set savename=%%P
set lastcd=%%Q
set /a q=q+1
echo. [!q!] !savename! - !lastcd!
set r=!r!!q!
)
)
pause
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
:LevelSave
cls & echo.Choose a save file: & echo.
SET savename=some name&SET lastcd=somelastcd&SET q=6
::#ECHO on
if exist q20731333.txt (
for /f "tokens=*" %%P in ('type q20731333.txt') do (
CALL :sub "%%P"
set /a q=q+1
echo. [!q!] !savename! - !lastcd!
set r=!r!!q!
)
)
GOTO :EOF
:sub
%~1
GOTO :eof
This should work... I've changed the filename for my testing...and instantiated variablenames.

How can a batch script do the equivalent of "cat << eof"?

In Linux (Bash) there is a very useful functionality for dumping literal text out to another file like this:
cat > see.txt << EOF
contents going into
my file
EOF
What I need is the equivalent for a Windows batch script. I haven't found this kind of functionality built-in, but I was thinking I could write a subroutine to do it (I don't want to rely on anything that isn't natively in Windows since XP), but I'm having trouble. Here's what I have so far with help from various sources:
call:catMyChunk myCustomText c:\see.txt
exit /b
goto:myCustomText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:myCustomText
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
set startLine=0
set endLine=0
for /f "delims=:" %%a in ('findstr -b -n !searchStart! %~dpnx0') do set "startLine=%%a"
for /f "delims=:" %%a in ('findstr -b -n !searchStop! %~dpnx0') do set "endLine=%%a"
set /a linesLeftToRead=%endLine% - %startLine%
del %outFile%
if "%linesLeftToRead%" LEQ "0" (
echo Error finding start and end delmieters for %searchStop% in catMyChunk routine
exit /B 1
)
setlocal DisableDelayedExpansion
for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
set "oneLine=!oneLine:*:=!"
set /a linesLeftToRead-=1
if !linesLeftToRead! LEQ 0 exit /B
echo(!oneLine!>>%outFile%
)
goto: EOF
So my requirement is that the chunk of text is output literally without any changes whatsoever (i.e. I don't want to have to escape blank lines, %, !, <, etc.). This code is doing almost everything I need, except I haven't found a way to get the exclamation points output properly. Here is the output I get, which isn't quite right:
This is my test file
Hope you like it.
<got these>
% and these %
these too
yeah
Edit:
For anyone wanting the modified version of the subroutine that now works, here it is:
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
set startLine=0
set endLine=0
for /f "delims=:" %%a in ('findstr -b -n !searchStart! %~dpnx0') do set "startLine=%%a"
for /f "delims=:" %%a in ('findstr -b -n !searchStop! %~dpnx0') do set "endLine=%%a"
set /a linesLeftToRead=%endLine% - %startLine%
del %outFile%
if "%linesLeftToRead%" LEQ "0" (
echo Error finding start and end delmieters for %searchStop% in catMyChunk routine
exit /B 1
)
setlocal DisableDelayedExpansion
for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
set "oneLine=%%a"
set /a linesLeftToRead-=1
setlocal EnableDelayedExpansion
set "oneLine=!oneLine:*:=!"
if !linesLeftToRead! LEQ 0 exit /B
echo(!oneLine!>>%outFile%
endlocal
)
endlocal
goto: EOF
Your code is missing a single endlocal in your FOR-loop.
You will then create for each loop a new local-context through the setlocal EnableDelayedExpansion, this will explode with some more lines in your text file.
Also, to preserve the exclamation marks (and also the carets) you need the toggling technique:
DOS batch files: How to read a file?
setlocal DisableDelayedExpansion
for /f "usebackq skip=%startLine% delims=" %%a in (`"findstr /n ^^ %~dpnx0"`) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
set "oneLine=!oneLine:*:=!"
set /a linesLeftToRead-=1
if !linesLeftToRead! LEQ 0 exit /B
echo(!oneLine!>>%outFile%
endlocal
)
+1, Interesting application! I modified your code for a simpler and faster version:
#echo off
call :catMyChunk myCustomText see.txt
exit /b
goto:myCustomText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:myCustomText
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
setlocal DisableDelayedExpansion
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
if exist %outFile% del %outFile%
set copyFlag=No
echo No> copyFlag
for /f "delims=" %%a in (%~f0) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
if !copyFlag! == No (
if !oneLine! == %searchStart% echo Yes> copyFlag
) else (
if !oneLine! == %searchStop% (
echo No> copyFlag
) else (
echo/!oneLine!>> %outFile%
)
)
endlocal
set /p copyFlag=< copyFlag
)
endlocal
goto :eof
I also created another version that looks more like the Linux version, that is, the lines to copy are placed directly after invoking the routine, and the execution continue after the last copied line. Of course, to make this possible the routine is not invoked via call, but entered with a goto, and when the routine ends it execute a goto %MYDELIM% instead of a "return" (exit /b or goto :eof). Also, because a goto can not have parameters, the "parameters" are defined in variables before the invocation.
#echo off
set searchStop=EndOfMyText
set outFile=see.txt
goto :catMyChunk EndOfMyText
This is my test file
Hope you like it.
<got these>
% and these %
! these too
yeah
:EndOfMyText
exit /b
:catMyChunk
::Before JUMP to this "function" define 2 vars: searchStop and outFile
::where is to be catted to %outFile%
::and text starts with goto :catMyChunk %searchStop%
::and ends with :%searchStop%
setlocal DisableDelayedExpansion
set searchStart=goto :catMyChunk %searchStop%
if exist %outFile% del %outFile%
set copyFlag=No
echo No> copyFlag
for /f "delims=" %%a in (%~f0) do (
set "oneLine=%%a"
setlocal EnableDelayedExpansion
if !copyFlag! == No (
if /I !oneLine! == !searchStart! echo Yes> copyFlag
) else (
if !oneLine! == :%searchStop% (
echo No> copyFlag
) else (
echo/!oneLine!>> %outFile%
)
)
endlocal
set /p copyFlag=< copyFlag
)
endlocal
goto %searchStop%
EDIT
This new version is even faster and now works with all special cases, including empty lines:
:catMyChunk
::Should call this function with 2 args, MYDELIM and outFile.txt
::where is to be catted to outFile.txt
::and text starts with <beginning of line>goto:MYDELIM
::and ends with <beginning of line>:MYDELIM
setlocal EnableDelayedExpansion
set searchStart=goto:%~1
set searchStop=:%~1
set outFile=%~2
if exist %outFile% del %outFile%
findstr /n ^^ "%~f0" > pipeline.txt
call :seekMyChunk < pipeline.txt
del pipeline.txt
exit /B
:seekMyChunk
set oneLine=:EOF
set /P oneLine=
if !oneLine! == :EOF goto startNotFound
set oneLine=!oneLine:*:=!
if not !oneLine! == %searchStart% goto seekMyChunk
:catNextLine
set oneLine=:EOF
set /P oneLine=
if !oneLine! == :EOF goto stopNotFound
set oneLine=!oneLine:*:=!
if !oneLine! == %searchStop% goto :eof
echo/!oneLine!>> %outFile%
goto catNextLine
:startNotFound
echo Error finding start delimiter for %searchStart% in catMyChunk
goto :eof
:stopNotFound
echo Error finding stop delimiter for %searchStop% in catMyChunk
goto :eof

Resources