Variable in variable batch - batch-file

Alright, I need help here. I have done this before where you have variable1 (let's say it's eat1=apple), variable2 (this is eat2=orange), and variable3 (appaleorange=apple and orange). I need it to do this:
echo Apple:%eat1%
echo Orange:%eat2%
echo Apple & Orange:%eat1%%eat2%
Now, you can see my problem. That above script wouldn't show the word and, only appleorange. That isn't my script and the reason I need this is because I have multiple variables with numbers in them. I have done this before and I forgot how... I know you can do a call and then multiple %'s.
In this case I want fterm variable to be fterm (not sure how to have it in there and not be a variable) and stermnum as a number that will be changed often on other parts of the script.
My code:
set stermnum=1
call set exsternum=%%fterm%%stermnum%%%
echo Selected term:%stermnum% ^(%exsternum%^)
Does anyone know what to do?
Thanks and sorry it was long :P
~Edit:I found it out... If it helps anyone I did:
call set exsternum=%%fterm%stermnum%%
Sorry for posting this even though I figured it out so fast

The OP appended a solution to the question, but it does not relate to the original question scenario, and it still has a bug.
Here is the OP's solution in terms of the original scenario:
set "eat1=apple"
set "eat2=orange"
set "appleorange=apple and orange"
call echo %%%eat1%%eat2%%%
For the actual code, I believe the OP wants to access an array of variables named fterm1, fterm2, fterm3, etc. And the number suffix is in a variable named stermnum.
call set exsternum=%%fterm%stermnum%%%
If fterm is itself a variable containing the base name of the array, then the solution becomes:
call set exsternum=%%%fterm%%stermnum%%%
But CALL is inefficient - Probably not noticeable with a single CALL, but it becomes painfully slow if executed thousands of times in a loop.
There is a much faster solution using delayed expansion. Delayed expansion must be enabled prior to being used.
Original scenario:
setlocal enableDelayedExpansion
set "eat1=apple"
set "eat2=orange"
set "appleorange=apple and orange"
echo !%eat1%%eat2%!
Actual code, interpretation 1:
setlocal enableDelayedExpansion
REM additonal code ...
set exsternum=!fterm%stermnum%!
Actual code, interpretation 2:
setlocal enableDelayedExpansion
REM additonal code ...
set exsternum=!%fterm%%stermnum%!

Related

Nesting Variables in batch

I have been having a real issue getting something that seems simple, but I can not seem to get a working answer.
Here is what I am doing:
Setting a variable with a specific name: ex. set "select=computer1"
I do a test and give that variable a value based on the result after using an if statement : ex set "%select%=1" This sets the variable %computer1% to 1
I want to see what the value of %computer1% is however all I know is %select%.
Is there any way I can get the value of %computer1% when only knowing %select%? %select% knows the name of the new variable but I need to know its value without being able to directly call it by hard coded name.
I thought a pipeline might work but I can not seem to figure this out.
Thanks all, I appreciate your help.
You need another layer of parsing. You can do it:
with delayed expansion:
setlocal enabledelayedexpansion
echo !%select%!
without delayed expansion:
call echo %%select%%

Windows Batch Variable inside variable

I'm not very good at code, but I'm trying to get something to work, which would make my life easier.
I need to get a variable to run from within a variable, if possible, but can't get it to work out.
set MAP1=Esseker
set %MAP1%MODS=#exile
-mod=%%MAP1%mods%
This is not the full code, but it's just a section showing what it is I am trying to do. -mod= is correct as it's part of a startup parameter.
You can do this by enabling delayed expansion.
Here's an example script:
#echo off
setlocal EnableDelayedExpansion
set MAP1=Esseker
set %MAP1%MODS=#exile
echo !%MAP1%MODS!
-mod=!%MAP1%MODS!
#echo on
Not sure if that -mod line should be a set, but I've copied what you had above, making the assumption that it's correct.

Batch File: Output variable to text file

I would like to output a variable to a text file. I have done this in my code, but I have one output within an if statement that I can't get to work.
if not exist "%TuningLog%" (
set Title=Tuning Parameters Saving Log
set LogTitle=--------- %Title% ---------
echo %LogTitle%>> "%TuningLog%"
)
All its supposed to do is check first for the existense of a log file and if it doesn't exist then I want to in the first instance append a title.
But all I get in the log file is " echo is off." If I don't use a variable and just place text there then it works fine.
Can anybody spot the problem? Thanks for reading and for any help!
UPDATE:
I changed my code to. I don't know much about delayed expansion, but I tried this and it happened to work...
if not exist "%TuningLog%" (
setlocal enabledelayedexpansion
set Title=Tuning Parameters Saving Log
set LogTitle=--------- !Title! ---------
echo !LogTitle!>> "!TuningLog!"
endlocal
)
If anyone can provide a reason as to why the first attempt didn't work and this did, then please inform this thread for the purposes of learning. Thank you!
because or early expansion. your variable gets replaced with its value at the moment the block starts. at this time, it is still undefined and thus empty. if you have echo on, you can watch this happening on screen. if you enable delayed expansion, as you did in your second example, it gets only expanded at the moment it is used, so it works as you expect variables to work in "real" programming languages.
EnableDelayedExpansion
causes Variables to be expanded in simple language it causes the system to treat the value of variable and not the variable name itself

Handling of variables in for-loop of a Windows batch file

I've been investigating this a lot with threads on StackOverflow and the like, but although I feel I'm close to the solution, this problem is giving me headaches.
What I'm trying to do: When a specific external hard drive is connected (distinguished via VolumeSerialNumber over WMIC), the drive letter is found out, and mirroring is done via robocopy. The script is executed via double-click. This is what I have so far:
FOR /F "skip=1" %%i in ('wmic logicaldisk where VolumeSerialNumber^="XXXXXXXX" get deviceid 2^>nul') DO (
SET y=%%i
IF [%y%]==[] GOTO hdmissing
SET "backuphd=%%i"
GOTO endfor
)
:endfor
robocopy "C:\Users\Herbert\Documents" "%backuphd%\Backup\Documents" /MIR
ECHO Backup done
ECHO end
:hdmissing
ECHO Couldn't find external drive
:end
PAUSE
This way, the external HD is never detected (%y% is always an empty string). However, if I execute the script twice in the same console session, everything works as expected. But I want it to work at the first execution.
This is what I've tried so far:
Put SET y=dummy at the beginning of the script. The HD is always found, triggering a backup to C: if the HD is not actually connected (apparently SET y=%%i doesn't alter y?)
Change %y% to !y! - The HD is always found, again
Generation 3,576 of the delayed expansion problem, compounded by a contaminated environment.
There's no setlocal apparent, so y remains set in the environment after the first run - hence the 'later run characteristics different from first run' phenomenon.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
The key in your case appears to be no setlocal enabledelayeexpansion and !y! - because !y! is just that - a literal string !y! unless delayedexpansion is invoked by the setlocal command.
(having said that,
IF [%%i]==[] GOTO hdmissing
would work just as well, as would
SET "y=%%i"
IF not defined y GOTO hdmissing
because if [not] defined var operates on the run-time value of var. "quoting the set arguments" ensures that any stray trailing spaces on the line are not included in the value assigned
)
As Magoo already pointed out, !y! doesn't work, since I forgot to enable Delayed Expansion. However, enabling it requires you to escape certain characters, which seemed quite irritating and tedious to me. It could be possible to just enclose the command in the FOR-loop with double quotes, as done in the two edits of this question, but I found out after solving it differently.
What I did was moving the block
IF [%y%]==[] GOTO hdmissing
SET "backuphd=%%i"
after :endfor. This way, it's outside of the for loop and %y% gets expanded accordingly.
Mind that this solution works only because I need just one item, and because of the programming flow.
Other useful approaches might be found in this question.
However, if you want to do the same thing: easier (though not as robust) solutions without WMIC might include
Putting a file with a specific name on the hard drive and checking for it with IF EXIST before backing up, hoping the user will not delete it, and the HD is connected to the same drive letter.
Putting the batch script on the drive itself and work with relative path names (optional: put a shortcut on the Desktop and hope again the drive is always under the same letter)

How to get a the directory path from a variable in a cmd batch file

Within my batch file I have a variable that contains a file path:
SET VAR1=C:\Folder1\Folder2\File.txt
I would like to extract on the directory structure and retreive:
C:\Folder1\Folder2\
I have read threads like this where I need to use %~dp0 where 0 I believe is passed as a parameter. I have tried %~dpVAR1 but that doesn't work. How can I get the output I'm looking for, but with a variable containing the file path?
Also, to make matters difficult, I have to perform all of this within an IF condition which means that once the variable is declared, I will need to refer to it with ! instead of % (I have declared setlocal enableextensions enabledelayedexpansion at the beginning of my script to allow for this).
Any help is much appreciated!
Thanks!
Andrew
You are attempting to use parameter expansion syntax on an environment variable - that cannot work. But it is relatively easy to do what you want.
Using a CALL (relatively slow):
(...
call :getPath "!var!" var
...
)
exit /b
:getPath
set "%2=%~dp1"
exit /b
Using FOR, assuming the variable does not contain any wildcards (fast)
(...
for %%F in ("!var!") do set "var=%%~dpF"
...
)
Using FOR, if the variable may contain wildcards (also fast)
(...
for /f "delims=" %%F in ("!var!") do set "var=%%~dpF"
...
)
Note 1: If the variable does not contain the full path, then all the solutions will attempt to resolve the name into an absolute path and will return the full absolute path. For example, if var contains foobar\test.txt, then the solutions will include the full path to the current directory, even if the file is not found. Something like c:\pathToCurrentDirectory\foobar\.
Note 2: All solutions above will remove all quotes from the path.
Note 3: A path could include the ! character, which will cause problems when expanding %~dp1 or %%~dpF because you have delayed expansion enabled. The delayed expansion will corrupt both ^ and ! if the value contains !. There is a solution that involves protecting both ! and ^. Here is a demonstration applied to the last solution above. The protection requires normal expansion, and since you are within a code block, it requires at least one CALL. It could be done without a subroutine, but it is easier with a subroutine. The subroutine assumes the variable is named var.
(...
call :getPath
...
)
exit /b
:getPath
set "var=!var:"=!"
set "var=!var:^=^^^^!"
set "var=%var:!=^^^!%" !
for /f "delims=" %%F in ("!var!") do set "var=%%~dpF" !
exit /b
I do believe (once again) many questions are on the same topic (string constraints, or splitting strings).
Instead of giving you the whole code, I'm going to give you a template and explain why %~dpVAR! didn't work.
Firstly, why %~dpVAR! did't work.
Before I get into modifiers, let's discuss parameters. You may know that batch files can parse parameters to each other. These parameters can be called by using a single percent sign (%) in front of the numbers 0-9. As far as I'm aware (someone might have made a way for more to be parsed), only 9 parameters can be parsed. You may think that is wrong (there's 10 parameters right?). Parameters 1-9 are parsed to the batch file (or function within one), %0 is the file path of the batch file (or function name). If you look, %~dp0 shares some (not really) resemblance to %0. This will be discussed below.
Secondly, the term %~dp0 has modifiers in it. Modifiers are things that modify variables (only in the case of parameters and those declared in for loops, you know the ones with double percent signs like %%i) and parameters. The modifier d expands the parameter to a drive letter only while p expands the parameter to a path only. You may think that these would contradict themselves, but parameters can be combined to create extremely wacky formats.
So, as you can see, you attempt at replacing 0 with your variable name failed because it's not specified for those sort of things.
Now, on to the template.
You can constrain variables (and put them into other variables) like this:
set variable=!variable:~offset,amount!
Don't worry if that seems confusing, I'm about to explain the components.
Firstly, notice that there is no /a switch. This is because this is not a mathematical function (don't really know why I added this). So, before I explain it, here's an example of what it would do to a variable name numbers that has the value of 0123456789.
set numbers=!numbers:~5,1!
By using that line of code, numbers would now equal 5. This is because it is recreating the variable with a smaller version of the original value (gee this is hard to explain). As you can see, there is a 5 where offset was on the template above. This is because it is skipping the first 5 characters and setting the variable as the next amount, or 1 character (I really hope you're getting this).
So basically, it sets a variable as a shorter value of a different (or the same) variable determined by the offset and the amount of characters to contain in it.
I really hope this helps because I probably wouldn't understand a word of this.
Can someone redirect this poor guy to a link explaining this better (I tried, ok!)?
Complete example of extracting paths from variable:
#echo off
set /p Fullpath="Specify full path: "
call :getPath %Fullpath% filename folder
echo %filename%
echo %folder%
pause
exit /b
:getPath
set "%2=%~nx1"
set "%3=%~dp1"
exit /b
Would this work:
SET VAR1=C:\Folder1\Folder2\File.txt
echo %var1%
Where Echo is the name of your exe.
%CD% may work as well: Echo %CD%

Resources