Using variables to access windows command file parameters - windows

I'm attempting to access a parameter passed to a function using a variable
name. I know of other ways to do this, such as using the SHIFT command,
but in this case I am trying it this way. I thought by using the
"setlocal enabledelayedexpansion" command I could do this because it permitted
the variable to be accessed using exclamation points around it rather than percent
signs. This is the line from the script below that isn't working:
set parm_value=%!parm_nr!
I thought that this would result in something like this:
set parm_value=%1
but instead, it is resulting in:
set parm_value=1
Does anyone know if this type of syntax is possible? Below is a test
script demonstrating the issue. Everything except this one item is
working correctly. Thank you in advance.
:BOJ
echo off
setlocal enabledelayedexpansion
cls
echo.
call :EXAMPLE_1 parm_1.1 parm_1.2 parm_1.3
goto :EOJ
:EXAMPLE_1
set nr_parms=0
for %%x in (%*) do set /A nr_parms+=1
set parm_nr=1
:EXAMPLE_1_LOOP
if %parm_nr% GTR %nr_parms% goto :EXAMPLE_1_END
set parm_value=%!parm_nr!
echo Parameter #%parm_nr% : %parm_value%
set /A parm_nr+=1
goto :EXAMPLE_1_LOOP
:EXAMPLE_1_END
echo.
exit /B 0
:EOJ
pause

try with
call set parm_value=%%!parm_nr!

Related

what could be wrong in this batch file

I'm trying to let the user enter numbers and if they miss one I want the program to drop an error message. However If not Defined doesn't work.
set /p aa=a11:
set /p ba=a12:
set /p ba=a12:
set /p ab=a21:
set /P bb=a22:
cls
echo antra matrica
echo.
set /p qq=b11:
set /p wq=b12:
set /p qw=b21:
set /P ww=b22:
for %%A IN (%aa%, %ba%, %ab%, %bb%, %qq%, %wq%, %qw%, %ww%) DO IF [%%A]==[] goto error
It ignores the for command. What could i do to make it work when all the variables are enterd blank?
just a different method:
set Count=0
for %%A IN (%aa%, %ba%, %ab%, %bb%, %qq%, %wq%, %qw%, %ww%) DO set /a Count+=1
if %Count% neq 8 goto error
This takes advantage of the fact that an undefined variable would not be processed with for (this was the problem with your original code)
Another advantage is, that now you could tell, how many of the variables were properly defined (if you want to know)
Aacini's solution will work, but two questions remain:
Why didn't "If not defined" work?
and
Why didn't the command you've posted work?
As you've provided it, cmd will interpret the for command as
for %%A in (aas_value, bas_value, abs_value, ...) do if
So had you entered 4,nothing,5,6... then the command line would be
for %%A in (4, , 5, 6...) do if
, and Space are seen as separators, so this would be resolved as
for %%A in (4separatorsequence5separatorsequence6...) do if
hence the missing value - er, goes missing.
If you'd used ...%var%... and if...defined then since 4,5 and 6 are not defined environment variables, you'd get "if not defined" acting unexpectedly (ie "does not work in the manner I expected but have kept to myself")
Another approach would be
for %%A IN ("%aa%", "%ba%", "%ab%",...) DO IF [%%~A]==[] goto error
which would be interpreted as
for %%A IN ("4"separatorsequence""separatorsequence"5",...) DO IF [%%~A]==[] goto error
Here, "4", "", "5" would each be assigned to %%A - including the quotes. The tilde (~) removes the enclosing quotes, so [%%~A] would be evaluated to [] as expected.

String replacement within FOR /F into batch file

There are a handful of questions on SO that look similar, but I cannot figure out some behaviour and I am looking for help.
Below is a snippet from a batch file I am trying to write which will load in a set of directories and potentially replace letter substitutions with an expanded path, e.g. the properties file might look like:
location1=C:\Test
location2=[m]\Test
Where location1 points to C:\Test and location2 points to C:\Program Files(x86)\MODULE\Test, because [m] is a shorthand to C:\Program Files(x86)\MODULE.
The batch script, to this point, is simply trying to read in the list of file paths and expand/replace the [m].
SET build.dir=%~dp0%
SET progfiles=%PROGRAMFILES(X86)%
IF "%progfiles%"=="" SET progfiles=%ProgramFiles%
SET local.properties=%build.dir%local.properties
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "tokens=1* delims==" %%i IN (%local.properties%) DO (
SET local.dir=%%j
SET local.dir=!local.dir:[m]=%progfiles%\MODULE!
echo !local.dir!
)
ENDLOCAL
Running this kicks out an error:
\MODULE was unexpected at this time.
If I replace the FOR with the following instead:
set test="[m]\Proj\Dir"
set test=!test:[m]=%progfiles%\MODULE!
echo %test%
I get the desired C:\Program Files(x86)\MODULE\Proj\Dir printed out...so I'm confused why it works fine outside of the FOR loop.
My understanding about delayed expansion is that it 'expands' at runtime...which you get to happen using !! instead of %% wrapped around the variable. Furthermore, as I'm creating the local.dir variable inside the FOR loop scope, I must use delayed expansion in order to access it with the updated value for the iteration.
I feel like the problem is using %progfiles%, like there's some special syntax I need to use in order to make it work but nothing is adding up for me. When I echo %progfiles%, it prints out as C:\Program Files(x86 -- note the missing trailing ).
Any ideas? Thanks
Tested suggestion:
D:\Projects\Test\Build>test
*** "D:\Projects\Test\Build\local.properties"
*** "","C:\Program Files (x86)"
[m]=C:\Program Files (x86)\MODULE
Adding quotes around the whole expression makes it work -- can't use other characters for some reason (like []) -- and since I want to append to the path later, we can safely remove the quotes afterwards:
SET local.dir="!local.dir:[m]=%progfiles%\MODULE!"
SET local.dir=!local.dir:"=!
Test this to see if you can nut out the issue:
The double quotes are to provide robust handling in a system with long file/path names.
The () are unquoted which are a problem in a batch script, when inside a loop.
#echo off
SET "build.dir=%~dp0%"
SET "progfiles=%PROGRAMFILES(X86)%"
IF "%progfiles%"=="" "SET progfiles=%ProgramFiles%"
SET "local.properties=%build.dir%local.properties"
echo *** "%local.properties%"
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "usebackq tokens=1* delims==" %%i IN ("%local.properties%") DO (
SET "local.dir=%%j"
echo *** "!local.dir!","%progfiles%"
SET "local.dir=!local.dir:[m]=%progfiles%\MODULE!"
echo !local.dir!
)
ENDLOCAL
pause
It has to do with the () characters that end up in your progfiles string. If you take them out, the substitution seems to work fine.
My suggestion is to ditch command for this particular purpose and use one of the other standard tools that Windows comes with. While my personal preference would be Powershell (since it's so much more powerful and expressive), you may just need something quick that you can integrate into existing cmd.exe stuff.
In that case, try the following VBScript file, xlat.vbs:
set arg = wscript.arguments
wscript.echo Replace(arg(0),arg(1),arg(2))
Your batch file then becomes something like, noting the inner for /f which captures the output of the VBS script and assigns it to the variable:
#echo off
SET build.dir=%~dp0%
set progfiles=%PROGRAMFILES(X86)%
if "%progfiles%"=="" set progfiles=%ProgramFiles%
set local.properties=%build.dir%local.properties
setlocal enabledelayedexpansion
for /f "tokens=1* delims==" %%i in (%local.properties%) do (
set local.dir=%%j
for /f "delims=" %%x in ('cscript.exe //nologo xlat.vbs "!local.dir!" "[m]" "%progfiles%\MODULE"') do set local.dir=%%x
echo !local.dir!
)
endlocal
Running that, I get the output:
C:\Test
C:\Program Files (x86)\MODULE\Test
which I think is what you were after.

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
)

How to include a value from an external bat script

I have a code that is shared by 6 different bat scripts below that takes an input argument. I wonder if I can externalize this piece in a seperate bat script and import it instead, so everytime I update this piece of code, I don't have to update all 6 bat scripts.
Code:
:Loop
IF "%1"=="" GOTO Prompt
SET VAR=%1
GOTO Continue
SHIFT
GOTO Loop
:Prompt
set /p VAR="Check which value? "
GOTO Continue
:Continue
Yes, using redirection.
Take this solution.bat file
set /p myvar=< somestring.txt
Where somestring.txt contains "abc"
myvar will now exist as an environment variable with abc.
Your code is supposed to set VAR to the first argument. If the first arg is missing then you want to prompt for a value.
First off, I would simplify your logic.
set "VAR=%~1"
if not defined VAR set /p "VAR=Check which value? "
Once simplified like above, I don't see why you would feel a need to externalize the code. But it could be done.
In your main script
call getArg.bat %1
And here is getArg.bat
set "VAR=%~1"
if not defined VAR set /p "VAR=Check which value? "
exit /b

Batch script: local variable from function1 to function2

Okay guys, let my try to explain my problem:
I start with a line from where I start 2 different functions
setlocal EnableDelayedExpansion
for %%i in ("C:\*.*") do (
call :function1 "%%~i"
call :function2 "%%~i"
)
goto :eof
In function1, at a certain point I DO a SET in a local environment:
setlocal EnableDelayedExpansion
...
...
set name1=blabla
endlocal & SET name=%name1%
echo %name%
goto :eof
The echo does return my variable. Now onto my problem.
I quit function one and i go to function 2 (see first code-segment)
I can't call the variable form here. I tried in the function2, I tried before function2 is called, but both didn't resolve the issue.
My guess is a have set only a local variable for function1. I search the nets but i read that the line "endlocal & SET name=%name1%" should have solved my issue.
I hope I have explained it well, all help appreciated!
I'm not sure where your problem lies since this works perfectly:
#setlocal enableextensions enabledelayedexpansion
#echo off
set name=ORIGNAME
for %%i in (1 2) do (
call :function1 %%i
echo in main %name% !name!
)
endlocal
goto :eof
:function1:
setlocal enableextensions enabledelayedexpansion
set name1=%1_blabla
endlocal & SET name=%name1%
echo in function %name%
goto :eof
outputting:
in function 1_blabla
in main ORIGNAME 1_blabla
in function 2_blabla
in main ORIGNAME 2_blabla
Are you certain that, when you used name in the main areas, you used !name! instead of %name%?
If you used the %name% variant, that would be evaluated when the entire for loop was read, not at the time when you used it (in other words, it would be blank). You can see that in the output of ORIGNAME in the main line.
I'm not certain that's the case since you are using delayed expansion. But, just in case, I thought I'd mention it. I always use delayed expansion and I always used the ! variants of the environment variables since it more closely matches how I expect a shell to work.
In any case, the code I've given works fine so you may want to fiddle with that to see if you can incorporate it into your own.
First a small working sample
#echo off
setlocal EnableDelayedExpansion
call :myAdd returnVar 1 2
echo 1. Percent %returnVar%
echo 1. Exlcam !returnVar!
(
call :myAdd returnVar 4 5
echo 2. Percent %returnVar%
echo 2. Exlcam !returnVar!
)
goto :eof
:myAdd
setlocal
set /a result=%2 + %3
(
endlocal
set %1=%result%
goto :eof
)
---- Output ----
1. Percent 3
1. Exlcam 3
2. Percent 3
2. Exlcam 9
The cause for the wrong result in "2. Percent" is a result of the expanding of %var%.
They are expanded at the time of parsing, before executing any line of the parenthesis block, so there is the old value in returnVar.
But that is also the cause why the returning of variables from a function works.
the endlocal removes all local variables, but the block (an ampersand works the same way)
is expanded before the "endlocal" is executed.
It's a good idea to test this issues with "echo on".

Resources