I have some code in which I want to use a FOR loop to handle a set of files.
As part of handling a file there's a FOR /F loop that reads it and appends data to an other file based on the file name.
In order to be able to set the output file name I have delayed variable expansion set on.
This is what the code should look like as I originally intended it to be:
setlocal enabledelayedexpansion
for %%f in (DataFolder\*.Ext) do (
set POI=%%~f
set POI=!JbPOI:DataFolder\=!
set POI=!JbPOI:.Ext=!
for /f "tokens=1,2,3 delims=," %%a in ("%%~f") do (
set CX=%%a
set CY=%%b
set FN=%%c
echo !FN!,9,!CX!,!CY! >> "DataFolder\!POI!.tmp"
)
)
endlocal
This code doesn't work because variable %%a, %%b and %%c never receive a value, %%a always has the same value as %%f.
I have read some articles about this issue but couldn't extract a solution from them that worked.
I have tried several things, none worked so far...
added a dummy outer loop to create variable %%a through %%j explicitly
inner FOR loop taken out and made it a subroutine
inner FOR loop taken out and made it a separate batch file
Can anybody please tell me how this can - or must - be solved?
setlocal enabledelayedexpansion
for %%f in (DataFolder\*.Ext) do (
set POI=%%~f
set POI=!JbPOI:DataFolder\=!
set POI=!JbPOI:.Ext=!
for /f "useback tokens=1,2,3 delims=," %%a in ("%%~f") do (
set CX=%%a
set CY=%%b
set FN=%%c
echo !FN!,9,!CX!,!CY! >> "DataFolder\!POI!.tmp"
)
)
endlocal
I'm not sure if you want to read the file "%%~f" , but I think this is what you need.
Sorry, but for the posted code i don't see the need for delayed expansion. All the needed data is being directly retrieved from the for replaceable parameters
setlocal enableextensions disabledelayedexpansion
for %%f in (DataFolder\*.Ext) do (
(
for /f "usebackq tokens=1-3 delims=," %%a in ("%%~f") do echo(%%c,9,%%a,%%b
) > "DataFolder\%%~nf.tmp"
)
endlocal
If the real code includes something not posted, maybe the answer from npocmaka will better fit in the problem.
Related
I wipped up some code that's supposed to delete files that don't have names beginning with the value of keep. I'm achieving this by putting the name of the file in tmpL1 and tmpL2 while substituting the value of keep with nothing. If tmpL1 and tmpL2 are different I'm keeping the file, otherwise it gets deleted.
setlocal enabledelayedexpansion
set keep=[File I want to keep]
for /F %%L IN ('dir /b *') do (
set tmpL1=%%L
set tmpL2=!tmpL1:%keep%=!
if !tmpL1!==!tmpL2! (
echo.[REMOVE]
) else (
echo.[KEEP]
)
)
This is working fine. However, when I put this code in a larger script, setting tmpL2 suddenly stops working. Instead of (part of) the file name tmpL2 now literally contains tmpL1:=.
Here is the script I want to use it in. The additional for-loops are only for going through a directory tree. The main function of the script is still the same.
setlocal enabledelayedexpansion
for /F %%G in ('dir /b *-snapshots') do (
set tmpG1=%%G
for /F %%H in ('dir /b !tmpG1!\*') do (
set tmpH1=%%H
for /F %%I in ('dir /b !tmpG1!\!tmpH1!\*') do (
set tmpI1=%%I
for /F %%J in ('dir /b !tmpG1!\!tmpH1!\!tmpI1!\*-SNAPSHOT') do (
set tmpJ1=%%J
set tmpJ2=!tmpJ1:~0,8!
for /F %%K in ('dir /b !tmpG1!\!tmpH1!\!tmpI1!\!tmpJ1!\*!tmpJ2!*.pom /O:N') do (
set tmp1=%%K
)
set keep=!tmp1:.pom=!
for /F %%L in ('dir /b !tmpG1!\!tmpH1!\!tmpI1!\!tmpJ1!\*!tmpJ2!*') do (
set tmpL1=%%L
set tmpL2=!tmpL1:%keep%=!
pause
if !tmpL1!==!tmpL2! (
echo.[REMOVE]
) else (
echo.[KEEP]
)
)
)
)
)
)
I also tried "lazy" delayed expansion by replacing set tmpL2=!tmpL1:%keep%=! with call set tmpL2=%%tmpL1:%keep%=%%. This also works in the small script, but when I apply it to the big one I get an error like "=%" can't be syntactically processed in this location (that's a free translation since my console is in German).
Anyone have an idea what's causing this?
You could try to change this line
set tmpL2=!tmpL1:%keep%=!
with
FOR /F "delims=" %%R in (""!keep!"") do set "tmpL2=!tmpL1:%%~R=!"
set tmpL2=!tmpL1:%keep%=!
When the for loop is parsed, since keep is at that time undefined, this will be reduced to
set tmpL2=!tmpL1:=!
Instead of:
set tmpL2=!tmpL1:%keep%=!
write:
call :SUB tmpL2 !tmpL1! !keep!
then at the bottom of your script, place this:
goto :EOF
:SUB return string search [replace]
set "tmpSub=%2"
set "%1=!tmpSub:%3=%4!"
goto :EOF
I have a batch file to Find and replace text string in a file with a portion of the its own file-name in multiple files within a folder using windows Batch script but it does not work and simply replace YYY with null or nothing. Any help appreciated. thank you
#echo off
SETLOCAL
SET stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
fOR /F "delims=" %%l IN (%%f) DO (
SET "line=%%l"
SET fname=%%~nf
SET fname=!fname:~6,3!
SETLOCAL ENABLEDELAYEDEXPANSION
set "x=!line:%stringtofindreplace%=%fname%!"
echo(!x!
ENDLOCAL)
)>%%~nf.txt
)
GOTO:EOF
here is updated code that still does not work
#echo off
SETLOCAL
SET stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
(
fOR /F "delims=" %%l IN (%%f) DO (
SET "line=%%l"
SET fname=%%~nf
SETLOCAL ENABLEDELAYEDEXPANSION
SET fname=!fname:~6,3!
SET "x=!line:%stringtofindreplace%=%fname%!"
echo(!x!
ENDLOCAL
)
)>%%~nf.txt
)
GOTO:EOF
You have a number of problems.
1) Your name substring computation attempts to use delayed expansion within your loop before you enable it.
2) The computed replacement string cannot be expanded using normal expansion. You need delayed expansion there as well. But you cannot use delayed expansion within delayed expansion. The trick is to transfer the inner value to a FOR variable.
3) You have got an extra, unbalanced ) after ENDLOCAL. I don't think it is causing any problems with the code you have posted, but you probably should remove it.
You are also computing the name substring once for every line, when it really only need be done once per file. This isn't a bug, but it is inefficient.
Here is corrected code.
#echo off
setlocal
set stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
setlocal enableDelayedExpansion
set "fname=%%~nf"
for /f "eol=: delims=" %%A in ("!fname:~6,3!") do (
endlocal
for /f "delims=" %%l IN (%%f) do (
set "line=%%l"
setlocal enableDelayedExpansion
set "x=!line:%stringtofindreplace%=%%A!"
echo(!x!
endlocal
)
)>"%%~nf.txt"
)
You still could have problems if any lines begin with ;. Also, empty lines will be stripped. Both limitations could be solved with a bit more code.
But even if you fix the limitations, it will be quite slow. It could be painfully slow if any files are large.
The code is much simpler, faster, and more reliable if you use my hybrid JScript/batch REPL.BAT utility:
#echo off
setlocal
set stringtofindreplace=YYY
for %%f in (*.fmw) do (
#echo Processing %%f...
setlocal enableDelayedExpansion
set "fname=%%~nf"
type "!fname!.fmw"|repl "%stringtofindreplace%" "!fname:~6,3!" li >"!fname!.txt"
endlocal
)
I need to make a batch file that can read a text file and I am using windows 7 ultimate 32 bit
I am currently using this code:
#ECHO OFF
for /f "delims=" %%x in (test.txt) do set "Var=%%x"
ECHO %Var%
pause
But this only reads the first line and I need it to read the whole thing. I need it to display the full text file.
Try this:
#ECHO OFF
SetLocal EnableDelayedExpansion
for /f "delims=" %%x in ('type test.txt') do (
set "Var=%%x"
ECHO !Var!
)
pause
You need to enclose the for loop with brackets if you are performing multiple commands inside the for loop. Besides that, SetLocal EnableDelayedExpansion will helps to expand the variable at execution time rather than at parse time.
Hope this helps.
Actually, this should read the whole file and set Var to the last line.
If you need to process the whole file, you have several options:
If you just need to do something for every line, then just use a block instead of the set "Var=%%x":
for /f "delims=" %%x in (test.txt) do (
rem Do something with %%x
)
If you need the complete file line-by-line in memory, use a counter and emulate arrays with lots of variables:
setlocal enabledelayedexpansion
set cnt=0
for /f "delims=" %%x in (test.txt) do (
set "ine[!cnt!]=%%x"
set /a cnt+=1
)
set /a numlines=cnt-1
and afterwards you can just use a for /l loop to access them again.
I would like to iterate a flat text file containing a Windows directory listing and run multiple commands against each line assigning each line to a variable. I then want to echo each resulting output from each command into a comma-delimited file. Yes, I understand batch programming might not be the best choice but am somewhat limited at the moment. Here is where I am at with it:
#echo off
setlocal
SETLOCAL ENABLEDELAYEDEXPANSION
:: There could be spaces in the filename, thus using delims
FOR /f "delims=?" %%a in (e:\multiline_textfile.txt) do (
set filename=%%a
CALL :PROG1
CALL :PROG2
CALL :PROG3
CALL :ENDPROG
:PROG1
FOR /f "delims=?" %%h in ('e:\apps\exe1.exe -s "!filename!"') do set result11=%%h
:PROG2
FOR /f "delims=?" %%i in ('e:\apps\exe1.exe -b"!filename!"') do set result2=%%i
:PROG3
FOR /f "delims=?" %%j in ('e:\apps\exe2.exe -c "!filename!"') do set result3=%%j
:ENDPROG
echo !result1!,!result2!,!result3!
)
---
Any insight would be greatly appreciated.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:: There could be spaces in the filename, thus using delims
FOR /f "delims=" %%a in (e:\multiline_textfile.txt) do (
set "filename=%%a"
CALL :PROG1
CALL :PROG2
CALL :PROG3
CALL :ENDPROG
)
echo here endeth your batch mainline
goto :eof
:PROG1
FOR /f "delims=" %%h in ('e:\apps\exe1.exe -s "!filename!"') do set "result1=%%h"
goto :eof
:PROG2
FOR /f "delims=" %%i in ('e:\apps\exe1.exe -b"!filename!"') do set "result2=%%i"
goto :eof
:PROG3
FOR /f "delims=" %%j in ('e:\apps\exe2.exe -c "!filename!"') do set "result3=%%j"
goto :eof
:ENDPROG
echo !result1!,!result2!,!result3!
goto :eof
You don't need the initial SETLOCAL - one is quite sufficient.
Labels are simply MARKERS in a batch program - they don't affect flow. The most common way to return in a CALLed routine is to GOTO :EOF where the colon is REQUIRED and the label :EOF is implicit and should NOT be declared.
Bad idea to attempt to use labels within a FOR loop like that. Might work with later versions, but not with earlier. Note the FOR loop's ending ) has been moved...
Whereas !var! works, it is not necessary in this case because each subroutine is essentially a whole new program which inherits the main environment as it stood at the CALL. Hence each !var! could be replaced by %var% and the SETLOCAL ENABLEDELAYEDEXPANSION need only be a SETLOCAL. You only need to use delayedexpansion where an ordinary environment variable's value is to be used after being changed in a compound statement (like a FOR over multiple lines, for instance)
I have a requirement where i'd like to read values from a .properties file
my properties file test.properties content
file=jaguar8
extension=txt
path=c:\Program Files\AC
From the above file I need to fetch jaguar or anything after =
Please help me. Thanks
For /F "tokens=1* delims==" %%A IN (test.properties) DO (
IF "%%A"=="file" set file=%%B
)
echo "%file%"
hope this could help
#echo off
FOR /F "tokens=1,2 delims==" %%G IN (test.properties) DO (set %%G=%%H)
echo %file%
echo %extension%
echo %path%
Note that there is no space after %%H. Else this causes a space to be appended, to file paths for example, and will cause file not found errors when the variables from the property files are used as part of a file path.Struggled for hours because of this!
A solution with support for comments (# style). See comments in code for explanation.
test.properties:
# some comment with = char, empty line below
#invalid.property=1
some.property=2
some.property=3
# not sure if this is supported by .properties syntax
text=asd=f
properties-read.bat:
#echo off
rem eol stops comments from being parsed
rem otherwise split lines at the = char into two tokens
for /F "eol=# delims== tokens=1,*" %%a in (test.properties) do (
rem proper lines have both a and b set
rem if okay, assign property to some kind of namespace
rem so some.property becomes test.some.property in batch-land
if NOT "%%a"=="" if NOT "%%b"=="" set test.%%a=%%b
)
rem debug namespace test.
set test.
rem do something useful with your vars
rem cleanup namespace test.
rem nul redirection stops error output if no test. var is set
for /F "tokens=1 delims==" %%v in ('set test. 2^>nul') do (
set %%v=
)
output from set test. (see above):
test.some.property=3
test.text=asd=f
The most important parts are:
the for-loop with the eol and delims option and
the if-checks that both variables %%a and %%b are set.
What you do in the for-loop with the variable and its value is certainly up to you - assigning to some prefixed variables was just an example. The namespacing approach avoids that any other global variable gets overridden.
For example if you have something like appdata defined in your .properties file.
I'm using this to get rid of an extra config.bat and instead using one .properties file for both the java app and some support batch files.
Works for me, but certainly not every edge case is covered here, so improvements welcome!
Try this
echo off
setlocal
FOR /F "tokens=3,* delims=.=" %%G IN (test.properties) DO ( set %%G=%%H )
rem now use below vars
if "%%G"=="file"
set lfile=%%H
if "%%G"=="path"
set lpath=%%H
if "%%G"=="extension"
set lextention=%%H
echo %path%
endlocal
I know this is ancient post but I would like to expand on toschug's great answer.
If the path in the .properties file would be defined as %~dp0 or any other variable that needs to be expanded first before using it, I recommend doing it the following way:
In the .properties file:
path=%~dp0
In the batch file you can then use it the following way (the code is to be used between the two for(s) defining one <=> cleanup one):
if "!test.path!" NEQ "" (
echo Not expanded path: !test.path!
call :expand !test.path! test.path
)
echo test.path expanded: !test.path!
pause
:expand
SET "%~2=%~1"
GOTO :EOF
Don't forget to use (at the start of the batch file):
SETLOCAL ENABLEDELAYEDEXPANSION
you can try this:
#ECHO OFF
#SETLOCAL
FOR /F "tokens=1* delims==" %%A IN (test.properties) DO (
ECHO %%A = %%B
)
#ENDLOCAL