How to put a Variable inside a variable in batch - windows

I'm making a bat file which add/load/rename savegame slots, and I had problem with some variables, the first variable is savegame number, the second variable is the name of the savegame, here is the code I've tried:
#echo off
set savename2=FortySeven
set nb=2
echo %savename%nb%%
pause
The result I have got is nb%

Either enable delayed expansion:
#Echo Off
Set "savename2=FortySeven"
Set "nb=2"
SetLocal EnableDelayedExpansion
Echo !savename%nb%!
Pause
EndLocal
Or, use Call for that expansion:
#Echo Off
Set "savename2=FortySeven"
Set "nb=2"
Call Echo %%savename%nb%%%
Pause

Related

Removing leading/trailing slashes in .BAT file ruins everything

I'm having a lot of trouble figuring out why my .bat file randomly closes... but I've narrowed it down to this:
IF %var:~-1%==\ SET var=%var:~0,-1%
IF %var:~0,1%==\ SET var=%var:~1%
Ideally what I'm eventually trying to accomplish is to remove any leading or trailing slashes or backslashes from %var%, which is set by user input.
The above lines work, but not when inside an IF statement when setlocal EnableDelayedExpansion is set AND when the variable is also set inside the IF statement.
For example, the following works if I remove the above lines, but crashes otherwise:
#echo off
setlocal EnableDelayedExpansion
set somevar=blah
if !somevar!==blah (
set /p var="-> "
IF %var:~-1%==\ SET var=%var:~0,-1%
IF %var:~0,1%==\ SET var=%var:~1%
echo !var!
)
pause
If I remove the IF condition, however, it does work:
#echo off
setlocal EnableDelayedExpansion
set /p var="-> "
IF %var:~-1%==\ SET var=%var:~0,-1%
IF %var:~0,1%==\ SET var=%var:~1%
echo !var!
pause
And if I keep the IF statement but move the set /p var="-> " outside of it, then it also works:
#echo off
setlocal EnableDelayedExpansion
set somevar=blah
set /p var="-> "
if !somevar!==blah (
IF %var:~-1%==\ SET var=%var:~0,-1%
IF %var:~0,1%==\ SET var=%var:~1%
echo !var!
)
pause
I know that when Delayed Expansion is enabled that I have to use ! instead of % for variables, but I've tried every combination of that on those lines to no avail, and I don't understand how they work enough to troubleshoot further.
And if there's a more efficient way to accomplish what I've described, by all means please mention it. I'm somewhat new to batch-writing.
As you've implied, the key to your problem is the use of delayed expansion.
When delayedexpansion has been invoked,
%var% refers to the value of var as it was when any code block (parenthesised sequence of instructions) was encountered (actually, var is simply replaced by its value at that time and then the instructions are executed)
!var! refers to the run-time value of var - that is, the value at the current time, having possibly been altered by the operation of the code block.
so, examining from your code
set /p var="-> "
IF %var:~-1%==\ SET var=%var:~0,-1%
IF %var:~0,1%==\ SET var=%var:~1%
echo !var!
This is executed as
set /p var="-> "
IF ==\ SET var=
IF ==\ SET var=
echo !var!
because the value of var at the start of the code is nothing, consequently it "crashes" because the if statement syntax is incorrect.
To fix the problem, use
set /p var="-> "
IF !var:~-1!==\ SET var=!var:~0,-1!
IF !var:~0,1!==\ SET var=!var:~1!
echo !var!
where each reference to var becomes the value as changed by the "set /p" or subsequent set operations.
However, set/p does not clear the variable if you simply press Enter. It leaves the variable unchanged (but its value happens to be nothing at the time)
Hence, a better approach is
set /p var="-> "
IF "!var:~-1!"=="\" SET "var=!var:~0,-1!"
IF "!var:~0,1!"=="\" SET "var=!var:~1!"
echo !var!
where the quotes around the if arguments ensure that the arguments are not empty and those around the set arguments ensure that the variable does not acquire any stray trailing spaces that may exist on the instruction line.

windows batch command nested variable

I have a requirement to use nested variables for creating a folder based on a environment variables.
Assume I have variables listed below:
%ABC_ASIA_LOCATION%
%ABC_EUROPE_LOCATION%
%ABC_US_LOCATION%
and I want to pass the country as variable like %ABC_%COUNTRY%_LOCATION%.
How do I achieve this in Windows utilizing batch scripting?
you have to enclose each variable into %:
set "ABC=ABC"
set "COUNTRY=EUROPE
set "LOCATION=MUNICH
echo %ABC%_%COUNTRY%_%LOCATION%
Result: ABC_EUROPE_MUNICH
Or if you just want Country as a variable, keeping the rest fixed:
echo ABC_%COUNTRY%_LOCATION
Result: ABC_EUROPE_LOCATION
or if you want the whole thing to be a variable (a variable name containing another variable), you have to use delayed expansion:
setlocal enabledelayedexpansion
set country=EUROPE
set "ABC_EUROPE_LOCATION=a town in southern Germany"
echo !ABC_%country%_LOCATION!
which gives you: a town in southern Germany
Note: setlocal has no effect outside of batchfiles, so delayed expansion works only:
- in batchfiles
- when the command prompt was started with delayed expansion enabled (cmd /v:on) (by default, the command prompt runs with delayed expansion disabled)
There are times when you need the nested variable to work inside a for loop, which already requires the !varname! syntax for the variable expansion. When this is the case, !ABC_%country%LOCATION!, will not work (reference Stephan's post on 9/6/2017 at 7:24). Neither will !ABC!country!_LOCATION!.
The following batch file demonstrates this. This is a somewhat contrived example to demonstrate the issue. In the subroutine, we can also set a variable to the nested value if you didn't want to do the work in the subroutine.
#echo off
setlocal enabledelayedexpansion
setlocal
set var1=value1
set var2=value2
set var3=value3
set var4=value4
set var5=value5
for %%A in (var1 var2 var3 var4 var5) do (
set varname=%%A
echo 1.This will not work: !varname!=!!varname!!
echo 2.This will not work: !varname!=%!varname!%
echo 3.This will not work: !varname!=!%varname%!
echo 4.This will not work: %varname%=%varname%
echo 5.This will not work: %varname%=%%varname%%
call:NestedVar %%A
call:getNestedVar new%%A %%A
echo new%%A=!new%%A!
echo.
echo.
)
goto:eof
:NestedVar
echo This will work: %1=!%1! (but only if setlocal enabledelayedexpansion is used)
goto:eof
:getNestedVar
REM Use: getNestedVar newVariableName varName
REM Will set newVariableName to the value of varName
echo Setting variable, %1=!%2!
set %1=!%2!
goto:eof

How to Reassess Batch variables?

Is it possible to reassess Batch variables?
Here an example what i want to do :
set a=Hello
set b=%a%
set a=Bye
echo %b%
rem Here, i want to show 'Bye' instead of 'Hello'
You could use delayed expansion to pass by reference.
setlocal enabledelayedexpansion
set "a=Hello"
set "b=a"
set "a=Bye"
echo !%b%!
... should output Bye. You're setting b to the variable name of a with this method. In the echo line, the batch thread first gets the value of b, which is a. It then expands the value of !a! via delayed expansion.
Be advised that if your values are likely to contain exclamation marks, you probably need to limit enabledelayedexpansion to the retrieval of your values only, avoiding having it active during the variable setting.
set "a=Hello"
set "b=a"
set "a=Bye"
setlocal enabledelayedexpansion
echo !%b%!
endlocal
You may store in variable b a reference to the value in a, and then use Delayed Expansion to access it:
#echo off
setlocal DisableDelayedExpansion
rem Store in "b" a *reference* to the value in "a"
set b=!a!
setlocal EnableDelayedExpansion
set a=Hello
echo Show the value in a: %b%
set a=Bye
echo Show the value in a: %b%

Cannot set argument value to a variable resulting empty in Windows batch script

I'm looping through all command-line arguments using SHIFT. I'm getting result of ECHO is off.. It is likely printing the empty variable.
:argLoopStart
SET paramName=
SET arg=%1
IF -%arg%-==-- GOTO argLoopEnd
IF %arg:~0,2%==-- (
SET paramName=%arg%
ECHO %arg%
ECHO %paramName%
)
SHIFT
GOTO argLoopStart
:argLoopEnd
By running the command fake-command --dbs=mydbname, I got this:
--dbs
ECHO is off.
According to the code above, ECHO %arg% prints --dbs and ECHO %paramName% prints ECHO is off. The line of SET paramName=%arg% is not working as I expected. %parameName% should print --dbs as well. However, it seems printing an empty variable.
You need to enable delayed expansion with SETLOCAL EnableDelayedExpansion at the top of your script:
Delayed Expansion will cause variables to be expanded at execution
time rather than at parse time, this option is turned on with the
SETLOCAL command. When delayed expansion is in effect variables may be
referenced using !variable_name! (in addition to the normal
%variable_name% )
#echo off
setlocal enabledelayedexpansion
:argLoopStart
set paramName=
set arg=%1
if -!arg!-==-- goto argLoopEnd
if %arg:~0,2%==-- (
set paramName=!arg!
echo !arg!
echo !paramName!
)
shift
goto argLoopStart
:argLoopEnd

Find and Replace inside for loop [batch script]

The below code works, echo test.test
set replaceWith=.
set str="test\test"
call set str=%%str:\=%replaceWith%%%
echo %str%
But, the below code echo ggg.hhhhh all the 4 times.
SET SERVICE_LIST=(aaa\bbb ccc\dddd eeee\fffff ggg\hhhhh)
for %%i in %SERVICE_LIST% do (
set replaceWith=.
set str="%%i"
call set str=%%str:\=%replaceWith%%%
echo %str%
)
What am I doing wrong here?
If you understand why your code uses call set str=%%str:\=%replaceWith%%%, then you should be able to figure this out ;-)
Syntax like %var% is expanded when the line is parsed, and your entire parenthesized FOR loop is parsed in one pass. So %replaceWith% and echo %str% will use the values that existed before you entered your loop.
The CALL statement goes through an extra level of parsing for each iteration, but that only partially solves the issue.
The first time you ran the script, you probably just got "ECHO is on." (or off) 4 times. However, the value of str was probably ggghhhhh and replaceWith was . after the script finished. You don't have SETLOCAL, so when you run again, the values are now set before the loop starts. After the second time you run you probably got ggghhhhh 4 times. And then from then on, every time you run the script you get ggg.hhhhh 4 times.
You could get your desired result by using CALL with your ECHO statement, and moving the assignment of replaceWith before the loop.
#echo off
setlocal
SET SERVICE_LIST=(aaa\bbb ccc\dddd eeee\fffff ggg\hhhhh)
set "replaceWith=."
for %%i in %SERVICE_LIST% do (
set str="%%i"
call set str=%%str:\=%replaceWith%%%
call echo %%str%%
)
But there is a better way - delayed expansion
#echo off
setlocal enableDelayedExpansion
SET "SERVICE_LIST=aaa\bbb ccc\dddd eeee\fffff ggg\hhhhh"
set "replaceWith=."
for %%i in (%SERVICE_LIST%) do (
set str="%%i"
set str=!str:\=%replaceWith%!
echo !str!
)
Please have a text book for Windows Command Shell Script Language and try this:
#ECHO OFF &SETLOCAL
SET "SERVICE_LIST=(aaa\bbb ccc\dddd eeee\fffff ggg\hhhhh)"
for /f "delims=" %%i in ("%SERVICE_LIST%") do (
set "replaceWith=."
set "str=%%i"
SETLOCAL ENABLEDELAYEDEXPANSION
call set "str=%%str:\=!replaceWith!%%"
echo !str!
ENDLOCAL
)

Resources