Storing variables name using for loop [duplicate] - batch-file

This question already has answers here:
windows batch files: setting variable in for loop
(3 answers)
Closed 7 years ago.
I want to get the list of all files inside of c:\test. My attempt is this:
set loc=c:\test
for /f %%i in(dir "%loc%" /b') do (
#set variable=%%i
echo %variable%
)
...but I'm getting back only one file name, n times. How to get all the files in that folder.

1. The reason you get back only 1 file name all the time is that you did not Setlocal EnableDelayedExpansion.
2. Check again you code, you did not add a single quotation mark before dir "%loc%" /b'.
3. Check again your code once more, you can't stick "in" and "(" like in(, this will absolutely ruin your code.
#echo off
Setlocal EnableDelayedExpansion
set "loc=c:\test"
for /f %%i in ('dir "%loc%" /b') do (
set "variable=%%i"
echo !variable!
)

You need to enable "delayed expansion" for this to work. If it isn't enabled, variables are evaluated exactly once, when the script is parsed. This is why you get the one filename n times.
Some notes:
Enable delayed expansion with SETLOCAL EnableDelayedExpansion
When delayed expansion is enabled, to take advantage of it, you need to use ! instead of % as variable delimiter, so your %variable% becomes !variable!
Loop variables like your %%i are an exception in that they will change their value even when delayed expansion is not enabled. Try ECHOing %%i in your original script (i.e. without SETLOCAL EnableDelayedExpansion) to see what I mean
Edit: dark fang correctly points out syntax errors in your script, which I didn't even catch - but from the behaviour your described, these were not in your script when you were trying run it, because it would just have errored out.
In the end you get:
SETLOCAL EnableDelayedExpansion
set loc=c:\test
for /f %%i in ('dir "%loc%" /b') do (
#set variable=%%i
echo !variable!
)

Related

how to set a variable for the value of " ping 8.8.8.8 | find /c "TTL=" " [duplicate]

This question already has answers here:
Assign output of a program to a variable using a MS batch file
(12 answers)
Closed 9 months ago.
I'm trying to assign the output of a command to a variable - as in, I'm trying to set the current flash version to a variable. I know this is wrong, but this is what I've tried:
set var=reg query hklm\SOFTWARE\Macromedia\FlashPlayer\CurrentVersion>
or
reg query hklm\SOFTWARE\Macromedia\FlashPlayer\CurrentVersion >> set var
Yeah, as you can see I'm a bit lost. Any and all help is appreciated!
A method has already been devised, however this way you don't need a temp file.
for /f "delims=" %%i in ('command') do set output=%%i
However, I'm sure this has its own exceptions and limitations.
This post has a method to achieve this
from (zvrba)
You can do it by redirecting the output to a file first. For example:
echo zz > bla.txt
set /p VV=<bla.txt
echo %VV%
You can't assign a process output directly into a var, you need to parse the output with a For /F loop:
#Echo OFF
FOR /F "Tokens=2,*" %%A IN (
'Reg Query "HKEY_CURRENT_USER\Software\Macromedia\FlashPlayer" /v "CurrentVersion"'
) DO (
REM Set "Version=%%B"
Echo Version: %%B
)
Pause&Exit
http://ss64.com/nt/for_f.html
PS: Change the reg key used if needed.
Okay here some more complex sample for the use of For /F
:: Main
#prompt -$G
call :REGQUERY "Software\Classes\CLSID\{3E6AE265-3382-A429-56D1-BB2B4D1D}"
#goto :EOF
:REGQUERY
:: Checks HKEY_LOCAL_MACHINE\ and HKEY_CURRENT_USER\
:: for the key and lists its content
#call :EXEC "REG QUERY HKCU\%~1"
#call :EXEC "REG QUERY "HKLM\%~1""
#goto :EOF
:EXEC
#set output=
#for /F "delims=" %%i in ('%~1 2^>nul') do #(
set output=%%i
)
#if not "%output%"=="" (
echo %1 -^> %output%
)
#goto :EOF
I packed it into the sub function :EXEC so all of its nasty details of implementation doesn't litters the main script.
So it got some kinda some batch tutorial.
Notes 'bout the code:
the output from the command executed via call :EXEC command is stored in %output%. Batch cmd doesn't cares about scopes so %output% will be also available in the main script.
the # the beginning is just decoration and there to suppress echoing the command line. You may delete them all and just put some #echo off at the first line is really dislike that. However like this I find debugging much more nice.
Decoration Number two is prompt -$G. It's there to make command prompt look like this ->
I use :: instead of rem
the tilde(~) in %~1 is to remove quotes from the first argument
2^>nul is there to suppress/discard stderr error output. Normally you would do it via 2>nul. Well the ^ the batch escape char is there avoids to early resolving the redirector(>). There's some simulare use a little later in the script: echo %1 -^>... so there ^ makes it possible the output a '>' via echo what else wouldn't have been possible.
even if the compare at #if not "%output%"==""looks like in most common programming languages - it's maybe different that you expected (if you're not used to MS-batch). Well remove the '#' at the beginning. Study the output. Change it tonot %output%==""-rerun and consider why this doesn't work. ;)
This is work for me
#FOR /f "delims=" %i in ('reg query hklm\SOFTWARE\Macromedia\FlashPlayer\CurrentVersion') DO set var=%i
echo %var%

Setting up variable in for loop in batch

I am fighting with little piece of code for last two days.
In this I am not able to set variable in a for loop.
I want to assign a filename to a variable for string manipulation.
echo off
for /f %%a IN ('dir /b *_ah.ttf') DO (
set /a fName=%%~na
echo %fName%
)
When I echo fName variable I get only last filename repeatedly number of times for for loop count.
(I want to pass this variable as an argument to some batch file as follows
ttfhnt --strong-stem-width=D -i %%a %fName:~0,-3%.ttf
but its failing due to above problem)
Can somebody help me please?
When the cmd parser reads a line or a block of lines (the code inside the parenthesis), all variable reads are replaced with the value inside the variable before starting to execute the code. If the execution of the code in the block changes the value of the variable, this value can not be seen from inside the same block, as the read operation on the variable does not exist, as it was replaced with the value in the variable.
This same behaviour is seen in lines where several commands are concatenated with &. The line is fully parsed and then executed. If the first commands change the value of a variable, the later commands can not use this changed value because the read operation replace.
To solve it, you need to enable delayed expansion, and, where needed, change the syntax from %var% to !var!, indicating to the parser that the read operation needs to be delayed until the execution of the command.
And set /A is only used for arithmetic operations
setlocal enabledelayedexpansion
for /f "delims=" %%a IN ('dir /b *_ah.ttf') DO (
set "fName=%%~na"
echo "!fName!" "!fName:~0,-3!"
)
edited to adapt to comments
While for command is able to execute a command (in the OP code, the dir...), retrieve its output and then iterate over the lines in this output, the original reason for the command is to iterate over a set of files. In this form, the code can be written as
setlocal enabledelayedexpansion
for %%a IN ("*_ah.ttf") DO (
set "fName=%%~na"
echo "!fName!" "!fName:~0,-3!"
)
Now, the for command replaceable parameter will iterate over the indicated set of files. (execute for /? for a list of all the command options).
But as foxidrive points, the problem with delayed expansion are the exclamation signs. Without delayed expansion, they are another normal character, but with delayed expansion they frequently become a problem when a value containig them is assigned/echoed.
A quick test
#echo off
setlocal enabledelayedexpansion
set "test=this is a test^!"
echo ---------------------
set test
echo ---------------------
echo delayed : !test!
echo normal : %test%
for /f "delims=" %%a in ("!test!") do echo for : %%a
Will show
---------------------
test=this is a test!
---------------------
delayed : this is a test!
normal : this is a test
for : this is a test
Obviously when the value is a file name, this behaviour will make the code find or not the file.
Depending on the case different solutions can be used, but usually it involves the activation / desactivation of the delayed expansion behaviour (beware, the endlocal removes any change in environment variables from the previous setlocal).
#echo off
setlocal enabledelayedexpansion
set "test=this is a test^!"
echo ---------------------
set test
echo ---------------------
echo delayed : !test!
rem Commuted to no delayed expansion
setlocal disabledelayedexpansion
echo normal : %test%
endlocal
rem Cancelled the initial enable delayed expansion
for /f "delims=" %%a in ("!test!") do endlocal & echo for : %%a
rem The last endlocal has removed the changes to the variable
echo no data : [%test%]

CMD file - delayed variable expansion

I am writing a CMD/batch file (running under Win-7 cmd.exe) and I seem to be getting hung up on delayed variable expansion.
I am using text file input that is in the form:
9 .CN=ISRJX.OU=Linc.OU=thisco.O=UCOM.T=UCOM. 8-20-13
10 .CN=FXXLISHER.OU=Linc.OU=thisco.O=UCOM.T=UCOM. 10-13-13
11 .CN=QXX004F.OU=Linc.OU=thisco.O=UCOM.T=UCOM. 10-14-13
12 *.CN=QXX1001OB.OU=Linc.OU=thisco.O=UCOM.T=UCOM. 10-15-13
as contents in "inputfile.txt". Purpose is to extract the first word after ".CN=", at this point in the process.
Note that I can't strip based on number of chars before "CN=" because the number of chars will vary.
My script is:
setlocal enableextensions enableDelayedExpansion
REM #echo off
for /f "tokens=3 delims==." %%a in (inputfile.txt) do (
set "acct =%%a"
echo. %%a,%acct%
)
endlocal
I've tried every set of combination of quote, !, % etc. and both enabled & disabled delayed expansion, and still can't get this to work. For the most part, when I use ! I end up echoing the actual !. i.e. "echo !acct!" will echo the actual text "!acct!".
I have read many examples and answers, here and elsewhere, about delayed variable expansion. I just can't figure out how to work around it in this example, where I want "acct" to expand within the loop.
Suspect this is a simple punctuation problem, but I'm out of ideas. When I run this, I see acct set to the value for %%a, but when it echoes, clearly it doesn't expand to the new value -- instead it will echo whatever it was set to previously, or blank.
I have also tried disabledelayedexpansion, which makes no difference in my results (including when I use !acct! instead of %acct%.)
Remove the space after the acct variable name and use the ! marks.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
for /f "tokens=3 delims==." %%A in (inputfile.txt) do (
set "acct=%%A"
echo. %%A,!acct!
)
endlocal

How to change an image tag url in multiple html files using batch script?

There are more than 10 html files with image tags. Every time we deploy our build onto test site we need to change the img source. for eg <img src=/live/Content/xyz.png />
to <img src=/test/Content/xyz.png />.
After looking around and reading for sometime, i have come up with the following batch script, however i cant figure out how do i go further from here :
for /r %%i in (*.html) do echo %%i
for %%f in (*.html) do (
FOR /F %%L IN (%%f) DO (
SET "line=%%L"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "x= <--------------------WHAT DO I SET HERE?
echo %x%
ENDLOCAL )) pause
This is my first batch script, could anyone please guide me in the right direction?
#ECHO OFF
SETLOCAL enabledelayedexpansion
for /r U:\ %%i in (*.html) do (
echo found %%i
SET outfile="%%~dpni.lmth"
(
SETLOCAL disabledelayedexpansion
FOR /F "usebackq delims=" %%L IN ("%%i") DO (
SET "line=%%L"
SETLOCAL ENABLEDELAYEDEXPANSION
SET "line=!line:/live/=/test/!
echo !line!
ENDLOCAL
)
ENDLOCAL
)>!outfile!
)
pause
GOTO :EOF
How about this development?
Notes:
I've modified your FOR/R to ECHO the HTML file being processed and use %%i rather than switching to %%f. U: is my RAMDRIVE; you'd need to modify that to suit.
outfile is set to generate a filename which matches the HTML filename, but with a .lmth extension (can't update in-place) - it gets that from the ~dpn prefixing the i, which means the drive, path and name of the file %%i. It's quoted to take care of potential spaces in the filename or pathname.
The next logical statement is (for /f...[lines] )>!outfile! which sends any echoed text to a NEW file !outfile!. The enabledelayedexpansion in the second physical line of the batch makes !outfile! the RUN-TIME value - as it is changed within the FOR r outer loop.
Since the actual HTML filename in %%i may contain spaces, it needs to be quoted, hence the 'usebackq' clause in the FOR/F. The delims= clause ensures that the ENTIRE line from the file "%%i" is applied to %%L - not just the first token (well, actually, makes the entire line the first token).
The SET command substitutes the string "/test/" for any occurrence of "/live/" in the RUN-TIME value of the variable lineand assigns the result to line. The resultant value is then ECHOd - which is redirected to outfile
Note that in your original, you would be assigning x in the set x= but echo %x% would have reproduced x as it stood when the line was PARSED because batch substitutes the value of any variable for %var% as part of the parsing phase. Consequently, the line would have become simply ECHO (since x would likely be unassigned) and bizarrely would have reported the echo state (Echo is OFF)
A couple of gatchas here. First, % and some other characters are notoriously hard to process with batch, so be careful. Next, FOR/F will bypass empty lines. This can be overcome if required. Third, this will replace ANY occurrence of /live/ in any case with /test/
Good luck!
Edit to support exclamation marks: 20130711T0624Z
Added SETLOCAL enabledelayedexpansion line and ENDLOCAL just before )>!outfile! to match

Delayed expansion doesn't work inside delayed expansion

I've got a script that does everything I expect it to do, apart from one line.
I've done similar before, but I can't get this one to work.
The code I've got is here
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
::Set Path to be folder of Sage Files
SET PATH=C:\Welcome\Progs\SitesDataSetups\GeorgeYarmouth
::set date variables
for /f "tokens=1" %%i in ('date /t') do set thedate=%%i
set mm=%thedate:~3,2%
set dd=%thedate:~0,2%
set yyyy=%thedate:~6,4%
::Set T_DAY variable to date in ddmmyy format
set T_DAY=%dd%%mm%%yyyy:~2%
c:
cd\
cd %path%
for /f "usebackq tokens=* delims= " %%P in (`dir sage*.csv /od /b`) do (
set SAGE=%%P
set SAGE2=!SAGE:~0,8!_EDITED
set EODNUM=!SAGE:~4,4!
for /f "tokens=* delims= " %%A in (%%P) do (
echo %EODNUM%
set S=%%A
***This line is the problem***
set S=!S:%T_DAY%=%EODNUM%!
echo.!S! >> %PATH%\TEST\!SAGE2!.csv
)
)
endlocal
I was expecting that is would take each line of the csv file and replace it with itself, except with a string replace of the current date with the variable EODNUM (which it does... only the variable is expanded before it is set, so is nothing)... The delayed expansion should solve this, but I can use this line of code
set S=!S:%T_DAY%=!EODNUM!!
because I think its too many !'s for CMD.
Am I missing something, or is there a better way to code this?? (I'm not a programmer of any kind, and most of the code I write comes from trial and error, and 'borrowing' from other scripts, so this may be a very messy way to do this).
Transfer the the value of !EODNUM! to a FOR variable, and then use your FOR variable as the replace string.
echo !EODNUM!
set "S=%%A"
for /f "delims=" %%E in ("!EODNUM!") do set "S=!S:%T_DAY%=%%E!"
echo.!S!>> %PATH%\TEST\!SAGE2!.csv
By way of explanation...
CMD reads (and does env var substitution), parses, and executes one top-level command at a time.
In your example, it reads the "for /f..." command all at once parsing and performing %var% substitution.
Once this is complete, it then executes the for loop, performing delayed !var! substitution.
Unfortunately, !var! substitution is not a do-substitution-until-none-left. This makes it hard (as in the answerer's solution) to perform the substitution into the !var:src=dst! value.
You will need a way that during execution you can get guaranteed substitution. This requires a for-statement, or something that involves reading and %var% substituting again. One way of doing this is to use the CALL :LABEL form where you can call to a specific label in your .cmd file and have this section do what you want:
...
call :GenS
...
and then:
:GenS
set S=!S:%T_DAY%=%EODNUM%!
goto :eof
BTW: I'm perplexed that you didn't notice the ECHO %EODNUM% not working in the loop as during the reading of the for loop all %var% substitutions are made.

Resources