I want to be able to get the next argument to compare to the current argument. So when the argVec is equal to "--define", I want to echo the next argument. I get the result "y" instead of "delivery".
My input is:
Cmd version version1 --define delivery
set inputArg=%*
setlocal enabledelayedexpansion
set Count=0
for %%x in (%inputArg%) do (
set /A Count+=1
set "argVec[!Count!]=%%~x"
)
for /L %%i in (1,1,%Count%) do echo %%i- !argVec[%%i]!
for /L %%x in (1,1,%Count%) do (
set /A y=%%x+1
#echo !y!
#echo !argVec[%%x]!
if "!argVec[%%x]!"=="--define" (
#echo !argVec[!y!]!
)
)
endlocal
When I added #echo off to the top of your script and ran it, I got the following output:
1- version1
2- --define
3- delivery
2
version1
3
--define
y
4
delivery
If I understand you correctly, the problem is the y on the third line from the bottom.
The reason you are getting y is because of #echo !argVec[!y!]!. This tokenizes as #echo, !argVec[!, y, !]!, which means "echo the contents of the !argVec[! variable, then echo y, then echo the contents of the ] variable. Since you don't have an !argVec[! variable or a ] variable, this reduces to "echo y".
To fix it, there is lots of good information at this SO answer. For your purposes, the important part of that post is this:
To get the value of an element when the index change inside FOR/IF enclose the element in double percents and precede the command with call.
Here is a version of your script that I think does what you want it to do:
#echo off
set inputArg=%*
setlocal enabledelayedexpansion
set Count=0
for %%x in (%inputArg%) do (
set /A Count+=1
set "argVec[!Count!]=%%~x"
)
for /L %%i in (1,1,%Count%) do echo %%i- !argVec[%%i]!
for /L %%x in (1,1,%Count%) do (
set /A y=%%x+1
#echo !y!
#echo !argVec[%%x]!
if "!argVec[%%x]!"=="--define" (
#call echo %%argVec[!y!]%%
)
)
endlocal
That prints:
1- version1
2- --define
3- delivery
2
version1
3
--define
delivery
4
delivery
I realize that echoing to the screen is probably not your final goal, so when you modify the script to do what you really want it to do, remember to use double percents around the whole "array", exclamation points around the index, and precede your command with call.
For example, if you want to add a compare condition, then set the contents of argVec[y] to a temporary variable from a call, and then use the temporary variable in your if, like this:
#echo off
set inputArg=%*
setlocal enabledelayedexpansion
set Count=0
for %%x in (%inputArg%) do (
set /A Count+=1
set "argVec[!Count!]=%%~x"
)
for /L %%i in (1,1,%Count%) do echo %%i- !argVec[%%i]!
for /L %%x in (1,1,%Count%) do (
set /A y=%%x+1
#echo !y!
#echo !argVec[%%x]!
#call set tmpvar=%%argVec[!y!]%%
if "!tmpvar!"=="--define" (
echo "found it"
)
)
endlocal
Output of the latest:
1- version1
2- --define
3- delivery
2
version1
"found it"
3
--define
4
delivery
You can not "nest" delayed expansions this way:
#echo !argVec[!y!]!
There are several ways to solve this problem, that are described here; the most efficient one is this:
for %%y in (!y!) do #echo !argVec[%%y]!
EDIT: Additional request stated in comment solved.
You may use the same method to get the value of argVec[!y!] and use it in any way you wish. For example:
for %%y in (!y!) do if "!argVec[%%y]!"=="delivery" echo true1
Related
Inside the for loop I'm trying to access the element at index count in CLs (this line of code: echo !!CLs[!count!]!!) , but I'm not sure how to do this. I don't really understand how expansion works in this case, so what you see below it me trying something out of no where.
#ECHO off
setlocal enableextensions enabledelayedexpansion
SET CLs[0]=#
SET /A count = 0
FOR /F "tokens=5" %%I IN ('some command') DO (
echo !!CLs[!count!]!! :: THIS LINE
IF NOT %%I == CLs[!count!] (
SET /A count += 1
SET CLs[!count!]=%%I
)
)
echo The item is %CLs[10]%
endlocal
Thanks
According to the post How does the Windows Command Interpreter (CMD.EXE) parse scripts? (see phase 5), the line echo !!CLs[!count!]!! cannot work, because the opening !! are collapsed to a single !, then !CLs[! is expanded to an empty string (assuming such variable is not defined), then count is returned literally, then !]! is expanded to an empty string and the final ! is dismissed. Or in other words, delayed expansion cannot be nested.
You can use call though to introduce another parsing phase, like this:
call echo %%CLs[!count!]%%
The line IF NOT %%I == CLs[!count!] ( ... ) is wrong, you must expand the right value too. However, call if will not help unfortunately, because if (like for and rem) is a special command that is recognised by the parser earlier than others, like call.
To work around that you can store the value of !count! in a for meta-variable, like %%J, for instance, to introduce another parsing phase, and use !CLs[%%J]! then, like this:
set /A "count=0"
for /F "tokens=5" %%I in ('some command') do (
for %%J in (!count!) do (
echo !CLs[%%J]!
if not "%%I" == "!CLs[%%J]!" (
set /A "count+=1"
set "CLs[!count!]=%%I"
)
)
)
Another yet slower possibility is to put the relevant code into a sub-routine:
set /A "count=0"
for /F "tokens=5" %%I in ('some command') do (
call :SUB !count!
)
goto :EOF
:SUB
echo !CLs[%~1]!
if not "%%I" == "!CLs[%~1]!" (
set /A "count+=1"
set "CLs[%~1]=%%I"
)
goto :EOF
You may also take a look at the post Arrays, linked lists and other data structures in cmd.exe (batch) script about how to deal with such pseudo-arrays.
ECHO ------------- START AT %time%
REM <!-- language: lang-dos -->
#ECHO Off
setlocal enableextensions ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q58209698.txt"
SET CLs[0]=#
SET /a clscnt[0]=0
SET /A count = 0
FOR /F "tokens=*" %%I IN ('type %filename1%') DO (
SET "processed="
FOR /f "tokens=1,2,3delims=[]=" %%a IN ('set cls[') DO IF /i "%%a"=="cls" (
IF "%%I"=="%%c" (SET /a clscnt[%%b]+=1&SET "processed=y")
)
IF not DEFINED processed SET /a count+=1&SET "cls[!count!]=%%I"&SET /a clscnt[!count!]=1
)
FOR /L %%a IN (0,1,%count%) DO ECHO !clscnt[%%a]! times !cls[%%a]!
ENDLOCAL
ECHO -------------------------Second way -----------------
#ECHO Off
setlocal enableextensions ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q58209698.txt"
SET CLs[0]=#
SET /a clscnt[0]=0
SET /A count = 0
FOR /F "tokens=*" %%I IN ('type %filename1%') DO (
SET "processed="
FOR /L %%a IN (0,1,!count!) DO (
IF "%%I"=="!cls[%%a]!" (SET /a clscnt[%%a]+=1&SET "processed=y")
)
IF not DEFINED processed SET /a count+=1&SET "cls[!count!]=%%I"&SET /a clscnt[!count!]=1
)
FOR /L %%a IN (0,1,%count%) DO ECHO !clscnt[%%a]! times !cls[%%a]!
ENDLOCAL
GOTO :EOF
I used a file named q58209698.txt containing some dummy data for my testing and chose to use the entire data line, having no suitable files where token 5 existed.
Note that as a bonus, I've added clscnt - an array of occurence-counts.
Shown: two separate ways of achieving the aim of finding/counting the unique tokens. Naturally, if the cls array is pre-loaded with the required tokens, then it's basic-programmer's-play to adjust the code to detect/report occurrences of those tokens.
The two methods are similar. In the first, set is used to list the established variables starting cls[. The first if ensures processing only the array-name cls, then either it's a repeat (set prcoessed to a value and increment the occurrences-counter) or it's a new value (when the for...%%a loop ends, processed is still undefined) so record it.
The second way is more direct, using the value of count to specifically interrogate the values in the cls array.
Here is my code for storing the words extracted from a log file into an array, which I want to use in the batch file later on.
cls
#echo off
set /a i=0
TIMEOUT 2
REM I want to save the words from newlog.txt into an array for later use in batch file.
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1,2,3 delims= " %%G IN (newlog.txt) DO ( set a[%i%]=%%H
& set /a i+=1 #echo !a[%i%]! )
#echo %i%
#echo a[%i%]
TIMEOUT 200
I just want to use them as global variables.
#echo off
set /a i=0
REM I want to save the words from newlog.txt into an array for later use in batch file.
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1,2,3 delims= " %%G IN (q48428047.txt) DO (
set a[!i!]=%%H&set /a i+=1)
SET a[
pause
GOTO :EOF
I used a file named q48428047.txt containing some dummy data for my testing.
Note that %i% will be replaced by the value of i *as it was when the *forwas encountered that is, 0.
Your second set within your parentheses is incorrect. It's missing the & before the #echo. Also, you appear to be attempting to increment i and then show the corresponding array entry, which makes no sense because you haven't yet stored anything in that array-entry, you've attempted to install it in the previous position. It won't work anyway, because %i% will be replaced by 0, not the varying value of i.
And whereas you may get the count-of-lines appearing on the screen, a[numlines] will not be defined.
Use pause to stop the batch for perusal. Preferably, run the command from the prompt, not by clicking.
The modified code reads each line of the file putting the first word in %%G, second in %%H and third in %%I. it then assigns %%H to a[currentlinenumber] and increments the line number in i.
The set a[ will display all environment variables whose names start with a[.
In addition to the answer already provided, if you really have a need to Echo each variable value immediately after it is Set then you would need to invoke a Call command:
#Echo Off
Rem Undefine any existing variables which begin with a[
For /F "Delims==" %%A In ('"(Set a[) 2>Nul"') Do Set "%%A="
Set "i=0"
ClS
SetLocal EnableDelayedExpansion
For /F "UseBackQ Tokens=2 Delims= " %%A In ("newlog.txt") Do (
Set "a[!i!]=%%A"
Call Echo "%%a[!i!]%%"
Set /A i+=1
)
If %i% GEq 1 Echo(&Echo %i% variables were defined&Echo(
(Set a[) 2>Nul
Timeout 200
I have a batch script which loops and I want to count how many cycles it has done.
This is how the script looks:
#echo off
title MyTitle
set cycles=0
:startpoint
echo %cycles%
(my command)
goto startpoint
I would like to be able to see the variable "cycles" increment by 1 each time it goes back to :startpoint, how do i do that?
To perform arithmetic operations in batch you need to use the /a switch with the set command:
#echo off
title MyTitle
set cycles=0
:startpoint
set /a cycles=cycles+1
echo %cycles%
...
(my command)
...
goto startpoint
Type set /? in cmd for more information.
Using this code
setlocal enableextensions enabledelayedexpansion
set /a count = 1
for /f "tokens=*" %%a in (config.properties) do (
set /a count += 1
echo !count!
)
endlocal
works for me, the reason because I was using %count% instead of !count! so I keep getting 1 instead of the expected output. So if using %% doesn't work for you, you can as well use !! to either display your output or do your calculations or comparisons.
well this worked for me.
#echo off
setlocal enabledelayedexpansion
SET /A i = 1
for /f "tokens=*" %%f in (temp.txt) do (
IF !i!==2 echo %%f
SET /a i+=1
)
I would like to print the following:
0
1
2
3
4
I have tried this:
ECHO OFF
FOR /L %%A in (1,1,5) DO (
SET /a "B=%%A-1"
ECHO %B%
)
However, this gives me:
4
4
4
4
4
How can I achieve the desired output while using both A and B in my code?
ECHO OFF
setlocal
FOR /L %%A in (1,1,5) DO (
SET /a "B=%%A-1"
call ECHO %%B%%
)
Since you are not using setlocal, B will be set to the value from the previous run. %B% will be replaced by 4 since B was set to 4 by the previous run. the call echo trick uses a parsing quirk to retrieve the current (run-time) value of the variable.
Here's "the official" way:
ECHO OFF
setlocal enabledelayedexpansion
FOR /L %%A in (1,1,5) DO (
SET /a "B=%%A-1"
ECHO !B!
)
In delayedexpansion mode, !var! retrieves the value of var as it changes at run-time. This is not without its drawbacks, but you'd need to read up on delayedexpansion for a guide on that matter.
I'm trying to read a file and output the lines of data into registry keys. The data collection works, but I don't understand the syntax required to increment the string values in the last loop.
#echo OFF
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq skip=1 delims=" %%a in (`"findstr /n ^^ C:\GetSID.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!" This removes the prefix
echo(!var:~76,63!>>C:\SIDoutput.txt
goto :EndLoop
)
:EndLoop
set /p SID= <C:\users\paintic\SIDoutput.txt
set KEY_NAME="HKEY_USERS\!SID!\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"
set Counter=1
for /f %%x in (C:\users\paintic\Networkprinters.txt) do (
set "Line_!Counter!=%%x"
set /a Counter+=1
if !Counter!==3 (Echo %line_counter%)
)
set /a counter2=!counter!-3
set counter=1
The part below is what I can't get to work. I'm trying to write LINE_1, LINE_2 and LINE_3 values from the previous loop to increment via the loop below. So VALUENAME should equal LINE_1, TYPE should = LINE_2's value and DATA should = LINE_3 on the first run and keep going up by 1 until the loop finishes (end of the file read)
`for /L %%i in (1,1,%counter2%) do (
set ValueName=%Line_!counter!%
set /a counter+=1
set Type=%Line_!counter!%
set /a Counter+=1
set Data=%Line_!counter!%
set /a Counter+=1
echo !ValueName!
echo !Type!
echo !Data!
REG ADD %KEY_NAME% /v !ValueName! /t !Type! /d !Data! /f
)
ENDLOCAL
Pause`
On searching for errors in batch file it is always helpful to use in first line #echo on or remove #echo off or comment this line with rem to see what cmd.exe really executes.
Command line interpreter fails on lines with set VariableName=%Line_!counter!% as the interpreter does not know what to expand first. I think it is not possible to create dynamically the name of an environment variable and reference next the value of this environment variable. This approach most likely does not work ever.
However, what you want to achieve can be done much easier directly in second loop as the following example demonstrates:
#echo off
setlocal EnableDelayedExpansion
rem Create data for demo example.
set "KEY_NAME=HKEY_USERS\S-1-5-20\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"
echo TestValue>"%TEMP%\Networkprinters.txt"
echo REG_SZ>>"%TEMP%\Networkprinters.txt"
echo Sample Data>>"%TEMP%\Networkprinters.txt"
echo AnotherValue>>"%TEMP%\Networkprinters.txt"
echo REG_DWORD>>"%TEMP%\Networkprinters.txt"
echo ^1>>"%TEMP%\Networkprinters.txt"
rem Now the loop follows which reads the data from the file line
rem by line and build the line for using command "reg.exe" to
rem add the data to registry of the user with the defined SID.
set Counter=1
for /f "usebackq delims=" %%x in ("%TEMP%\Networkprinters.txt") do (
if "!Counter!"=="1" (
set "ValueName=%%x"
) else if "!Counter!"=="2" (
set "ValueType=%%x"
) else (
set "ValueData=%%x"
rem Echo the command instead of really executing "reg.exe".
echo reg.exe ADD %KEY_NAME% /v "!ValueName!" /t !ValueType! /d "!ValueData!" /f
set Counter=0
)
set /a Counter+=1
)
rem Delete the text file created for demo example.
del "%TEMP%\Networkprinters.txt"
endlocal
This solution is much easier than what you have tried and can be maybe even more simplified.