Windows Batch File Expansion Variables - windows

I'm having an issue with a Batch File. Basically, I would like to seek ahead by 1 in a for loop and use that value to reference the parameter at that position and then assign it to a variable which I can then use later, see code sample below.
Example: set myVar=%1+1
Where %1 is param name, and %2 would be param value.
::Batch file sample
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set count=0
set HasParam=0
set ParamValue="null"
set paramValPos=0
for %%i in (%*) do (
set /a count=!count!+1
if /i "%%i"=="MyParam" (
set /a HasParam=1
set /a paramValPos=!count!+1
::The next line is where I Need Help, it's currently incorrect!
set ParamValue=%!paramValPos!
)
)
if %HasParam%==1 (
echo "Parameter Value: %ParamValue%"
)
pause
Example call from command line: prog.bat MyParam=5
Now I know that I can access it at pos 2, like:
::Sample batch file
#echo off
echo "Param Name: %1"
echo "Param Value: %2"
pause
However, this is not what I want, as there are more parameters and some are optional and they can also be passed in, in any order.
Thanks for your assistance.

call set "ParamValue=%%!paramValPos!"

If I understood your request correctly, you want the next parameter after a given one. The Batch code below do that:
#echo off
set "HasParam="
set "ParamValue="
for %%i in (%*) do (
if defined HasParam (
if not defined ParamValue (
set ParamValue=%%i
)
) else if /i "%%i"=="MyParam" (
set HasParam=yes
)
)
if defined HasParam (
echo "Parameter Value: %ParamValue%"
)
pause

Related

Print and assign array values to another variable in batch file

I face some problem while trying to print array values as shown below:
#echo off
setlocal EnableDelayedExpansion
set args=
set /A argc=0
SET /A argn=0
for %%a in (%*) do (
SET args[!argn!]=%%a
SET /A argn+=1
)
FOR %%q in (%*) DO (
echo !args[%argc%]! //not able to print the value
call echo %%args[!argc!]%% // this worked
if "%%q" == "--snap" (
set /A argc+=1
set SNAP=!args[%argc%]! //this didn't work
)
if "%%q" == "--source" (
set /A argc+=1
call SET "SOURCE=%%args[!argc!]%%" //this didn't work too
)
set /A argc+=1
)
Using this segment of code prints only the first value of the array but the other method of using for /l works fine.
How do i correct this?
Is it possible to store this array value in any other variable? If so, how?
You are trying to echo a variable you haven't set, it will therefore be blank.
#Echo Off
SetLocal EnableDelayedExpansion
Set argc=0
For %%q In (%*) Do (
Set "args[!argc!]=%%q"
Rem The next line is for information only
Call Echo=%%args[!argc!]%%
Set/A argc+=1
)
Rem take a look at the variables
Set args[
Timeout -1
Assuming delayedexpansion has been invoked and argn has been set to #args+1 as reported in comments,
set /a argn-=1
for /L %%q in (0,1,%argn%) do echo !args[%%q]!
set /a argn+=1
would be my preference.

Windows batch replace last found substring

I faced with problem using windows cmd. I need found and replace last found substring. For instance I have a string - #192.168.0.1:1521:SID. I need to replace the last colon with a slash and recieve #192.168.0.1:1521/SID.
How can I do this?
It looks like you have a fairly well defined format: IPAddress:Number:SID, so this could be treated as replacing the 2nd : with a /
#echo off
set val=#192.168.0.1:1521:SID
for /f "tokens=1,2,* delims=:" %%a in ("%val%") do set newval=%%a:%%b/%%c
echo %newval%
yourcommand %newval%
You can optimize if the format is always the same (e.g. always the 4th char from the end) but as a general solution I would code it like below.
set result=
set left=
set right=#192.168.0.1:1521:SID
:loop
call :sub1 "%right%"
if %result% equ 1 goto :loop
#echo %left%/%right%
goto :eof
:sub1
for /f "delims=: tokens=1*" %%i in ("%~1") do (
if ["%%j"]==[""] (
set /a result=0
goto :eof
)
if ["%left%"]==[""] (
set left=%%i
) else (
set left=%left%:%%i
)
set /a result=1
set right=%%j
)
goto :eof
Explanation:
The code in sub1 splits the argument on the first colon from the left unless there is no colon in the argument - in this case it sets the result to 0 and returns.
The left part is added to the left-variabel, the right part is set to the right-variable.
The main loop calls the sub sub1 until there is no more split and you're done.

Windows Batch Command : How to dereference FOR loop variable to check if that variable is SET in Environment Variable

I'm writing a batch command script where in there is a check for Environment variables. I need to write a FOR loop by passing all the required variables and then validate if it is defined or not and if it is not defined then prompt the value for that key and set that variable permanently.
Problem is that I could not dereference the loop variable and check it in Environment variable.
Sample code is as below:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%G IN (JBOSS_HOME, JAVA_HOME, ANT_HOME, PERFORCE_PATH, P4CLIENT) DO (
ECHO.
ECHO. Loop Item : %%G
:: Call a function by sending each value to check if it is set in ENVIRONMENT Variables, if not then add it persistently.
CALL:validateAndUpdate %%G
)
GOTO:EOF
:validateAndUpdate
:: Now I have to check if passed value is available in ENVIRONMENT variable or not
:: echo %~1 will print value like JBOSS_HOME
:: Below IF condition always substitues to IF ("JBOSS_HOME" == []) and it always returns true
:: but could not find syntax to use it to DE-reference and check if that key is set.
:: Ex: IF %JBOSS_HOME% == []
IF ("%~1" == []) (
ECHO.
ECHO. %~1 is empty
SET /p value="Enter value for '%~1' : "
:: Set that key value pair persistently using SETX
SETX %~1 "%value%"
) ELSE (
ECHO.
ECHO. %~1 is available as ENVIRONMENT variable
)
GOTO:EOF
ENDLOCAL
To check whether a variable is defined, use the defined keyword in an if statement. help if for more information.
If I may make another suggestion, it might be better to display a folder chooser for the user rather than asking him to key pathnames manually. To that end, save this proof of concept with a .bat extension and try it out. See whether it works like you want:
#if (#a==#b) #end /* JScript multiline comment
:: based on https://stackoverflow.com/a/15906994/1683264
:: batch portion
#echo off
setlocal enabledelayedexpansion
for %%G in (windir, temp, foo, bar) do (
if not defined %%G (
call :chooser %%G "Locate directory for %%G."
) else echo %%G is already defined as !%%G!
)
goto :EOF
:chooser <var_to_set> <dialog_title>
for /f "delims=" %%I in ('cscript /nologo /e:jscript "%~f0" "%~2"') do (
rem :: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
rem :: Remove the "echo" from this next line when you are satisfied
rem :: that it will do what you intend.
rem :: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
echo setx %~1 "%%~I"
)
goto :EOF
:: JScript portion */
var shl = new ActiveXObject("Shell.Application");
var folder = shl.BrowseForFolder(0, WSH.Arguments(0), 0, 0x00);
WSH.Echo(folder ? folder.self.path : '');
After you're satisfied the simulation does what you intend, remove echo from the :chooser subroutine.
See this page for more methods of launching a file or folder chooser from a .bat script, and see this GitHub Gist for more details and more examples of JScript / batch hybrids.
#echo off
setlocal enableextensions disabledelayedexpansion
for %%g in (JBOSS_HOME, JAVA_HOME, ANT_HOME, PERFORCE_PATH, P4CLIENT) do (
echo(
echo Testing %%g
if defined %%g (
echo %%g is available as ENVIRONMENT variable
) else (
echo %%g is empty
set /p "value=Enter value for '%%g' : " && (
setlocal enabledelayedexpansion
for /f "delims=" %%v in ("!value!") do (
endlocal
SETX %%g "%%v"
)
)
)
)
As already indicated, if defined varname is the "correct" way to check if a variable is defined.

Escape asterisk in Windows Batch File's FOR Loop

When running the following code in a windows batch file everything works aside from the string containing the asterisk, which is skipped. Checking the passed parameters by number (i.e. echo(%~6) I can see the asterisk - it's only when passed to the FOR loop that I have an issue:
#echo off
setlocal enableextensions enabledelayedexpansion
call:Concat cmd "this is a demo" " of concat functionality." " Hopefully it will work;" " but it doesn't when I pass an" " * asterisk" " character"
echo !cmd!
#goto:end
#goto:eof
:Concat
::Concatenates a given list of strings without including their quotes
::1 - output variable
::2* - strings to concat
echo(%*
set /a xx=0
set Concat_tempFlag=0
set Concat_temp=
for %%A in (%*) do (
set /a xx=!xx!+1
echo !xx! - %%A
if !Concat_tempFlag!==1 (
set Concat_temp=!Concat_temp!%%~A
) else (
set Concat_tempFlag=1
)
)
set "%~1="%Concat_temp%""
#goto:eof
:End
echo(Bye
exit /b 0
I've attempted for /F (tokens=*) %%A in ('echo(%*') do ( as suggested here: Batch FOR loop with asterisk (and variations thereof) but with no luck. Any ideas? Thanks in advance.
Found the solution here: I need to match or replace an asterisk * in a batch environmental variable using only native Windows commands. Is this possible?
Full code below:
#echo off
setlocal enableextensions enabledelayedexpansion
set DEFAULT_AsteriskMarker=_xAsteriskMarkerx_
call:Concat cmd "this is a demo" " of concat functionality." " Hopefully it will work;" " but it doesn't when I pass an" " * asterisk" " character"
echo !cmd!
#goto:end
#goto:eof
:Concat
::Concatenates a given list of strings without including their quotes
::1 - output variable
::2* - strings to concat
set Concat_StringsToConcat=%*
echo(%Concat_StringsToConcat%
call:AsteriskFix Concat_StringsToConcat
set /a xx=0
set Concat_tempFlag=0
set Concat_temp=
for %%A in (%Concat_StringsToConcat%) do (
set /a xx=!xx!+1
echo !xx! - %%A
if !Concat_tempFlag!==1 (
set Concat_temp=!Concat_temp!%%~A
) else (
set Concat_tempFlag=1
)
)
set "%~1="!Concat_temp:%DEFAULT_AsteriskMarker%=*!"
#goto:eof
:AsteriskFix
::https://stackoverflow.com/questions/11685375/i-need-to-match-or-replace-an-asterisk-in-a-batch-environmental-variable-using
set AsteriskFix_temp=!%~1!
if "%~2"=="" (
set AsteriskFix_marker=%DEFAULT_AsteriskMarker%
) else (
set AsteriskFix_marker=%~2
)
call:StrLen AsteriskFix_temp AsteriskFix_len
for /l %%x in (0,1,%AsteriskFix_len%) do if not "!AsteriskFix_temp:~%%x,1!"=="" if "!AsteriskFix_temp:~%%x,1!"=="*" (
set /a AsteriskFix_plusone=%%x+1
for /l %%y in (!AsteriskFix_plusone!, 1, !AsteriskFix_plusone!) do (
set AsteriskFix_temp=!AsteriskFix_temp:~0,%%x!%AsteriskFix_marker%!AsteriskFix_temp:~%%y!
)
)
set "%~1=!AsteriskFix_temp!"
#goto:eof
:StrLen
::http://www.dostips.com/DtCodeCmdLib.php#strLen
set "StrLen_str=A!%~1!" &:: keep the A up front to ensure we get the length and not the upper bound
::it also avoids trouble in case of empty string
set "StrLen_len=0"
for /L %%A in (12,-1,0) do (
set /a "StrLen_len|=1<<%%A"
for %%B in (!StrLen_len!) do if "!StrLen_str:~%%B,1!"=="" set /a "StrLen_len&=~1<<%%A"
)
IF "%~2" NEQ "" SET /a %~2=%StrLen_len%
#goto:eof
:End
echo(Bye
exit /b 0
Thanks to James K
The link you provided leads to the right answer:
There is no way to preserve an asterisk (nor a question mark) in the set of a normal (no /F option) FOR command (they are always changed to file names); you need to separate the parameters in a FOR /F command. If you also want to process each parameter in a FOR loop, then the second FOR can NOT be in the same context, so you must CALL a subroutine to change the context

Find a substring (filepath) from a string containing variable order arguments

%params% contains a variable set of arguments:
/tidy /log /truncate /convert D:\libdir
or maybe
/log /tidy D:\cyclea\libfolder /test /convert /truncate
for everything but the (currently single) filepath element I use it such:
if "%params%"=="%params:log=%" goto :DontLogit
if NOT "%params%"=="%params:/tidy=%" (call tidysub: & do something else )
Now I want to extract the filepath element and use it as an argument to a command eg chdir
I've played with, but I'm weak with CMD string manipulation and for loops.
I'd like to keep the order of params variable.
For info it comes from here:
FOR %%s IN (%*) DO (set params=!params! %%s)
#ECHO OFF
SETLOCAL
SET swparams=log tidy test convert truncate
FOR %%i IN (%swparams% other) DO SET "%%i="
FOR %%i IN (%*) DO (
SET "used="
FOR %%p IN (%swparams%) DO (IF /i "/%%p"=="%%~i" SET %%p=Y&SET used=Y)
IF NOT DEFINED used CALL SET other=%%other%% "%%~i"
)
ECHO =============paramsreport===========
FOR %%i IN (%swparams%) DO IF DEFINED %%i (ECHO %%i:set) ELSE (ECHO %%i:clear)
ECHO other=%other%
FOR %%i IN (%other%) DO ECHO %%i or %%~i
GOTO :EOF
Here's a way that should be extensible for you.
Simply set you switch-parameters into the list in swparams.
the parameter-names and OTHER are set to [nothing] to ensure they're not already set in the environment.
Ech supplied parameter is applied to %%i in turn, and matched against each defined swparam in turn. the variable USED is cleared before the match and if the match (of /switchparametername is found, the switch parameter is set and the USED flag is set.
if the used flag is not set gainst any of the switch parameters, then a parsing trick is used to accumulate any unrecognised strings into OTHER
The "%%~i" mechanism first dequotes the item in %%i, then quotes it. In this way, it ends up quoted, regardless of whether it originally has quotes or not.
The /i on the if performs a case-insensitive match.
hence running this batch
thisbatch /tidy "C:\some filename with spaces.txt"
will yield TIDY set to Y, LOG,test, convert, truncate not set and other set to "C:\some filename with spaces.txt"
#echo off
setlocal EnableDelayedExpansion
rem Get the single filepath element (with colon in second character):
set params=/tidy /log /truncate /convert D:\libdir
set filepath=
for %%a in (%params%) do (
set par=%%a
if "!par:~1,1!" == ":" (
set filepath=%%a
)
)
if defined filepath (
echo Filepath = %filepath%
) else (
echo Filepath not given
)
echo/
rem Get multiple filepath elements in an *array*:
set params=/log /tidy D:\cyclea\libfolder /test /convert D:\libdir /truncate
set i=0
for %%a in (%params%) do (
set par=%%a
if "!par:~1,1!" == ":" (
set /A i+=1
set filepath[!i!]=%%a
)
)
echo There are %i% filepath elements:
for /L %%i in (1,1,%i%) do (
echo %%i- !filepath[%%i]!
)
You may review a further description on array management at this post: Arrays, linked lists and other data structures in cmd.exe (batch) script

Resources