Loop through files in folder, replace content and Save as new Name - batch-file

I need to loop through filed end with .edi in my folder, replace a character in the content and then save the file in another folder with "_updated"on the end.
e.g.
C:/Test/FileName.edi replace ' in file with ^ and save the file into C:/Test/Output/FileName_Updated.edi
I've tried the following code and it works up until the saving the filename part, I've got confused somewhere, I don't usually write batch scripts:
#echo off
setlocal enabledelayedexpansion
for %%f in (C:\Test\*.edi) do (
set "input=C:\Test\"
SET "output=C:\Test\Output\"
for %%a in (%%f) do (
set "output=%output%%%~na_update.%%~xa"
)
(for /f "delims=" %%i in (%%f) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:'=^!"
echo(!line!
endlocal
)))>> %output%
)

Figured it out with help from aschipfl
#echo off
setlocal enabledelayedexpansion
for %%f in (C:\Users\CHRW\Desktop\EDILocalTest\*.edi) do (
SET "output=C:\Users\CHRW\Desktop\EDILocalTest\Output\"
for %%a in (%%f) do (
set "outputfile=!output!%%~na_update%%~xa"
)
(for /f "delims=" %%i in (%%f) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:'=^!"
echo(!line!
endlocal
))>> !outputfile!
)

#echo off
setlocal enabledelayedexpansion
for %%f in (C:\Test\*.edi) do (
set "input=C:\Test\"
SET "output=C:\Test\Output\"
(for /f "delims=" %%i in (%%f) do (
set "line=%%i"
rem setlocal enabledelayedexpansion
set "line=!line:'=^!"
echo(!line!
rem endlocal
)))>> "%output%%%~nf_update.%%~xf"
)
Since you were changing the value of output within the loop, the redirection should have been to !output! not %output% - the changed value of output, not the value of output at the time the outer for loop was parsed.
Since %%f contains a filename, there's no need to re-parse it. Easier to construct the output filename in-line
Since delayedexpansion has been invoked at the start of the procedure, there's no need to re-invoke it and close the new invocation. I've REMmed-out those lines as it may be that you are presenting abbreviated code.

Related

Batch file for loop fails to execute inside for loop

the task is simple to take input from the file "input.txt" which contains the keyword that need to be replace in the source file "source.txt" and create the newfile with the name of the keyword. Could you please suggest what is wrong.
#echo off &setlocal
setlocal enableextensions disabledelayedexpansion
set "search=POP"
set "source=dev500_ABC_eu.env"
for /f %%a in (input.txt) do (
set "replace=%%a"
set "newfile=devga520_%replace%_eu.env"
for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
)>"%newfile%"
)
Here in the input.txt, suppose it has "PQR". So it should replace "POP" in the file with "PQR" and the new file shoud generate with the name dev500_PQR_eu.env
Input file.txt
line 1 --> PQR
line 2 --> XYX
line 3 --> NOB
line 4 --> BOB
Output expected: 4 different files after replacing the character "ABC" with the input file text eg: whereevr "ABC" is there it should be replaced by PQR inside the dev500_ABC_eu.env and the newfile to be renamed with the text.
dev500_PQR_eu.env --> replaced name and content as well by PQR.
dev500_XYX_eu.env
dev500_NOB_eu.env
dev500_BOB_eu.env
Any help will be appreciated. Thanks.
...
set "source=dev500_ABC_eu.env"
for /f %%a in (input.txt) do (set "replace=%%a")
set "newfile=devga520_%replace%_eu.env"
(
for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
)
)>"%newfile%"
Please see delayed expansion items on SO for more info. Any %var% within a code block (parenthesised series of lines) will be replaced by the value of var at the time the block is first encountered.
You need to set replace outside of the block.
Your revision has clarified matters.
#ECHO Off
SETLOCAL
SET "search=POP"
set "source=dev500_ABC_eu.env"
:: This is a replacement source file I used for testing...
set "source=c:q45416169_1.txt"
for /f %%a in (c:q45416169.txt) do (
set "replace=%%a"
set "newfile=devga520_%%a_eu.env"
CALL DEL %%newfile%% >NUL 2>nul
for /f "delims=" %%i in (%source%) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%%a!"
>>!newfile! echo(!line!
endlocal
)
)
I used a file named q45416169.txt containing your data for my testing.
I used a file named q45416169_1.txt containing some dummy text data for my testing.
I left the assignment of replace in the code, but it's now redundant.

Batch, use wildcard in set

I want to put a batch file to modify a line in a file in a GPO.
The problem I have is the path is different for each user.
So, I tried to use a wildcard in my path but it doesnt work.
This bat is working:
#echo off &setlocal
setlocal enabledelayedexpansion
set "search=test"
set "replace=test2"
set "textfile=%appdata%\Thunderbird\Profiles\5xu9scdm.default\prefs.js"
set "newfile=%appdata%\Thunderbird\Profiles\5xu9scdm.default\prefs2.js"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
set "line=!line:%search%=%replace%!"
echo(!line!
))>"%newfile%"
del %textfile%
rename %newfile% prefs.js
endlocal
But if I use a wildcard in the set, it doesnt work anymore.
#echo off &setlocal
setlocal enabledelayedexpansion
set "search=test"
set "replace=test2"
set "textfile=%appdata%\Thunderbird\Profiles\*.default\prefs.js"
set "newfile=%appdata%\Thunderbird\Profiles\*.default\prefs2.js"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
set "line=!line:%search%=%replace%!"
echo(!line!
))>"%newfile%"
del %textfile%
rename %newfile% prefs.js
endlocal
How can I fix this ?
You approach does not work, because wild-cards can only occur in the last element of a path. In addition, for /F is not capable of handling wild-cards. So you need to wrap around a for /D loop to resolve the wild-cards, like this (supposing there is only a single matching directory *.default):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "search=test"
set "replace=test2"
set "rootdir=%appdata%\Thunderbird\Profiles\*.default"
set "textfile=prefs.js"
set "newfile=prefs2.js"
for /D %%j in ("%rootdir%") do (
> "%%~j\%newfile%" (
for /F "usebackq delims=" %%i in ("%%~j\%textfile%") do (
set "line=%%i"
setlocal EnableDelayedExpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
)
)
> nul move /Y "%%~j\%newfile%" "%%~j\%textfile%"
)
endlocal
exit /B
What I changed besides inserting the for /D loop:
delayed expansion is toggled within the loop, so exclamation marks in the text files are not lost;
all paths are properly quoted; to use a quoted file path in for /F, usebackq is required;
the replacement of the original file by the modified one is done by a single move command rather than del plus rename;

bat script for replacing strings creates empty file

I'm using this bat file to modify a value in a web.config from httpTransport to httpsTransport. It works well if I direct my output to another file. If I try to overwrite my file it creates an empty file.
#echo off &setlocal
set "search=httpsTransport"
set "replace=http123Transport"
set INTEXTFILE=D:\teste_bat\Web.config
set OUTTEXTFILE=D:\teste_bat\WebTemp.config
(for /f "delims=" %%i in ('findstr "^" "%INTEXTFILE%"') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
))>>"%OUTTEXTFILE%"
del %INTEXTFILE%
rename %OUTTEXTFILE% %INTEXTFILE%
Any help would e apreciated
The following code fails in case both INTEXTFILE and OUTTEXTFILE point to the same file, because the output redirection > prepares the output file at the beginning, so it creates an empty file, which is then read by findstr:
set "INTEXTFILE=D:\teste_bat\Web.config"
set "OUTTEXTFILE=D:\teste_bat\Web.config"
> "%OUTTEXTFILE%" (
for /f "delims=" %%i in ('findstr "^" "%INTEXTFILE%"') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
)
)
Replacing > by >> does also not work, because this appends the new data to the original file.
To overcome this, you have got two options:
To write to a different file and to replace the original file by the new one at the end:
set "INTEXTFILE=D:\teste_bat\Web.config"
set "OUTTEXTFILE=D:\teste_bat\WebTemp.config"
> "%OUTTEXTFILE%" (
for /f "delims=" %%i in ('findstr "^" "%INTEXTFILE%"') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
)
)
move /Y "%OUTTEXTFILE%" "%INTEXTFILE%"
This is the recommended variant due to better performance.
To ensure that the file is read before the output redirection is applied:
set "INTEXTFILE=D:\teste_bat\Web.config"
set "OUTTEXTFILE=D:\teste_bat\Web.config"
for /f "delims=" %%i in ('findstr "^" "%INTEXTFILE%" ^& ^> "%OUTTEXTFILE%" rem/') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
>> "%OUTTEXTFILE%" echo(!line!
endlocal
)
This is worse in performance since there are multiple file access operations (appending to the file per each loop iteration due to >>), but it prevents the need of a temporary file. The portion > "%OUTTEXTFILE%" rem/ depletes the file after being read by findstr, then it is appended to later in the loop body.

batch : Substring in loop with 2 variables

I have a loop that loops over files, gets the actual file name (not including the whole path) and tries to check if that file name exists in some list.
the code I have is:
setlocal enabledelayedexpansion enableextensions
for /R %%j in (*.c) do (
set MYVAR=%%j
set actualFileName=%%~nj
if NOT "%MY_FILE_LIST%"=="!MY_FILE_LIST:%actualFileName%=!" set "TOCOMPILE=!TOCOMPILE! %MYVAR%"
this code does not work since the actualFileName is accessed with % instead of !.
but !MYVAR:~!actualFileName!! doesn't work either.
what can i do?
You can directly use the for replaceable parameter modifiers to get the needed information
for /r %%j in (*.c) do (
echo actualFileName is %%~nj
)
Where %%~nj is the name, without extension, of the file being referenced in %%j. See for /? for the full list
edit to adapt to comments
setlocal enableextensions enabledelayedexpansion
for /r %%j in (*.c) do (
if not "!MY_FILE_LIST:%%~nj!"=="%MY_FILE_LIST%" (
set "TOCOMPILE=!TOCOMPILE! "%%~fj""
)
)
This should do the job IF no file contains a exclamation in its name. If this can not be ensured
setlocal enableextensions disabledelayedexpansion
for /r %%j in (*.c) do (
setlocal enabledelayedexpansion
if not "!MY_FILE_LIST:%%~nj!"=="%MY_FILE_LIST%" (
for /f "delims=" %%a in ("!TOCOMPILE! ") do (
endlocal
set "TOCOMPILE=%%a"%%~fj""
)
) else endlocal
)
setlocal enabledelayedexpansion enableextensions
for /R %%j in (*.c) do (
set MYVAR=%%j
set lastIndex= some calculation to find last index of /
for /f "tokens=* delims=" %%# in ("!lastIndex!") do (
set actualFileName=!MYVAR:~%%#!
)
)
use another nested FOR

Loop through CSV file with batch - Space issue

I have a csv file like this
name,sex,age
venu,m,16
test,,22
[EDIT]
name could have comma also
"venu,gopal",m,16
I want to handle if sex is nothing and save it to another file.
I have a script like this
#Echo Off
For /F "usebackq tokens=1-3 delims=," %%a in (test.csv) Do (
echo %%a, %%b, %%c >> test-new.csv
)
But for the third record, I am getting %%b as 22 which should be space. How to fix this?
[EDIT2]
I have tried as per that link. I am not sure what I am doing wrong. I am getting same issue. Please check it once.
#echo off
setlocal DisableDelayedExpansion
For /F "usebackq tokens=1-3 delims=" %%x in (C:\somefile.csv) Do (
setlocal EnableDelayedExpansion
set "var=%%x"
set "var=!var:"=""!"
set "var=!var:^=^^!"
set "var=!var:&=^&!"
set "var=!var:|=^|!"
set "var=!var:<=^<!"
set "var=!var:>=^>!"
set "var=!var:,=^,^,!"
set var=!var:""="!
set "var=!var:"=""Q!"
set "var=!var:,,="S"S!"
set "var=!var:^,^,=,!"
set "var=!var:""="!"
set "var=!var:"Q=!"
For /F "tokens=1-3 delims=," %%a in ("!var:"S"S=","!") Do (
endlocal
echo %%~a, %%~b, %%~c
setlocal EnableDelayedExpansion
pause
)
endlocal
)
This is a bit tricky, as multiple delims will be condensed to a single delim.
So you need to replace them before to a unique delim sequence.
#Echo Off
setlocal DisableDelayedExpansion
For /F "usebackq tokens=1-3 delims=" %%a in (test.csv) Do (
set "line=%%a"
setlocal EnableDelayedExpansion
set "line="!line:,=","!""
For /F "tokens=1-3 delims=," %%a in ("!line!") Do (
echo %%~a, %%~b, %%~c
)
)
This enclose each column into quotes, and with the %%~a the quotes will be removed later
EDIT: The solution for embedded commas
In this case it's only a bit different than the solution for how to split on ';' in CMD shell
#echo off
setlocal DisableDelayedExpansion
For /F "usebackq tokens=1-3 delims=" %%x in (test.csv) Do (
set "var=%%x"
setlocal EnableDelayedExpansion
set "var=!var:^=^^!"
set "var=!var:&=^&!"
set "var=!var:|=^|!"
set "var=!var:<=^<!"
set "var=!var:>=^>!"
set "var=!var:,=^,^,!"
rem ** This is the key line, the missing quote is intention
call set var=%%var:""="%%
set "var=!var:"="Q!"
set "var=!var:^,^,="C!"
set "var=!var:,,=,!"
set "var=!var:""="!"
set "var="!var:,=","!""
for /F "tokens=1-3 delims=," %%a in ("!var!") do (
endlocal
set "col1=%%~a"
set "col2=%%~b"
set "col3=%%~c"
setlocal EnableDelayedExpansion
if defined col1 (
set "col1=!col1:"C=,!"
set "col1=!col1:"Q="!"
)
if defined col2 (
set "col2=!col2:"C=,!"
set "col2=!col2:"Q="!"
)
if defined col3 (
set "col3=!col3:"C=,!"
set "col3=!col3:"Q="!"
)
echo a=!col1!, b=!col2!, c=!col3!
endlocal
)
)
using a string editor like SSED, I have overcome this issue by creating a temp file where I have replaced ",," with ",-," twice, then regarding a "-" as having been an empty field in the original file...
ssed "s/,,/,-,/ig;s/,,/,-,/ig" file1.csv > file1.tmp
Then the tokens are allocated correctly. If you need to edit the temp file and then return to a CSV, then use...
ssed "s/,-,/,,/ig;s/,-,/,,/ig" file1.tmp > file1.csv
This seems much simpler than doing in flight string replacements by token and having subroutines/etc.

Resources