bat script for replacing strings creates empty file - batch-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.

Related

Reading File Name using batch

I'm working on a new project, and I would like some help.
I have a script that I put together and it works great, but would like to see if we can update it
What I need help with is making the batch files read 2 parts of it's own file name and use that to match and replace content of many different .txt files
these are my bat script names, I have made over 100 individual batch scripts
(50) Kentucky.bat
(60) New_York.bat
(90) Texas.bat
I have a total of 7 different .txt files and each txt files looks like this
cmmd.txt
| Kentucky
| New_York
| Texas
| Houston
This is how I setup my script, I'm ok with the setup, it does what it needs to
#echo off
setlocal enableextensions disabledelayedexpansion
set "search=Kentucky"
set "replace=50"
set "SOURCE=%~dp0New Folder 1"
set "textFile1=cmmd.txt"
set "textFile2=cwab.txt"
set "textFile3=ecbc.txt"
set "textFile4=elic.txt"
set "textFile5=tcpd.txt"
set "textFile6=uadu.txt"
set "textFile7=urdm.txt"
for /f "delims=" %%i in ('type "%source%\%textFile1%" ^& break ^> "%source%\%textFile1%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%source%\%textFile1%" echo(!line:%search%=%replace%!
endlocal
)
for /f "delims=" %%i in ('type "%source%\%textFile2%" ^& break ^> "%source%\%textFile2%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%source%\%textFile2%" echo(!line:%search%=%replace%!
endlocal
)
for /f "delims=" %%i in ('type "%source%\%textFile3%" ^& break ^> "%source%\%textFile3%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%source%\%textFile3%" echo(!line:%search%=%replace%!
endlocal
)
for /f "delims=" %%i in ('type "%source%\%textFile4%" ^& break ^> "%source%\%textFile4%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%source%\%textFile4%" echo(!line:%search%=%replace%!
endlocal
)
for /f "delims=" %%i in ('type "%source%\%textFile5%" ^& break ^> "%source%\%textFile5%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%source%\%textFile5%" echo(!line:%search%=%replace%!
endlocal
)
for /f "delims=" %%i in ('type "%source%\%textFile6%" ^& break ^> "%source%\%textFile6%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%source%\%textFile6%" echo(!line:%search%=%replace%!
endlocal
)
for /f "delims=" %%i in ('type "%source%\%textFile7%" ^& break ^> "%source%\%textFile7%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%source%\%textFile7%" echo(!line:%search%=%replace%!
endlocal
)
call "%~dp0\(60) New_York.bat"
So this will be the end results after I run the first .bat and it calls the rest
cmmd.txt
| 50
| 60
| 90
| Houston
So I would like is to set this up where set "search=Kentucky" and set "replace=50" are setup by using the file name of the .bat file instead of me editing each Search and Replace
If you noticed that I added a call at the end and it works great, but is there a way for a script to call the next .bat file without me having to edit each .bat file
as you can see, I named my files by numeric order, and each .bat will call the next .bat file
(50) Kentucky.bat - this will call (60) New_York.bat
(60) New_York.bat - this will call (90) Texas.bat
(90) Texas.bat - the last one will not have a call
Having something like that will help save so much time, since all I would have to do is rename the .bat files as I need them, and that's it
I do appreciate any help and for all your time
meanwhile I will continue to make my .bat files
Repeating code is bad (error-prone and hard to maintain). Consolidate and use parameters where needed (where the code differs). This leaves you with just one script and a textfile to maintain the replacement parameters, looking like:
50,Kentucky
60,New_York
90,Texas
The code:
#echo off
setlocal
REM get vars from csv
for /f "usebackq tokens=1,2 delims=," %%a in ("replacements.csv") do call :replace "%%~a" "%%~b"
:: REM get vars from parameters
:: call :replace "%~1" "~2"
goto :eof
:replace
REM replace in all matching files:
set "source=%~dp0New Folder"
for %%a in ("%source%\*.txt") do (
for /f "delims=" %%i in ('type "%%a" ^& break ^> "%%a" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%%a" echo(!line:%~2=%~1!
endlocal
)
)
In case you need it, I included a way to use parameters (commented out with ::. Use either the for loop (reading the textfile) or the parameters like
replace.bat 20 "New Jersey"
(both methods support spaces)
See for /? for the ~<modifer><var> modifiers and call /? for the %~<number> parameters.

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

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.

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;

Replacing strings with batch file command

I have many files that are name "12739-5468768.xml", what they have in common is the "12739", inside these files I want to replace every & with " AND " and every </ with nothing. I tried many commands and python command but it doesn't seem to operate on my computer.
#echo off
setlocal
setlocal enabledelayedexpansion
set "search=&"
set "replace= AND "
set "textfile=12739*"
set "newfile=Output.txt"
(
for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
set "line=!line:%search%=%replace%!"
echo(!line!
)
) > "%newfile%"
del %textfile%
rename %newfile% %textfile%
endlocal
Solution for a single file
This handles also !^, empty lines and lines beginning with ; in the file content.
#echo off
setlocal
call :replaceFile "12739-5468768.xml"
exit /b
:replaceFile
set "search=&"
set "replace= AND "
set "textfile=%~1"
set "newfile=%~1.replaced"
setlocal DisableDelayedExpansion
(
for /f "usebackq delims=" %%i in (`findstr /N "^" "%textfile%"`) do (
set "line=%%i"
setlocal EnableDelayedExpansion
set "line=!line:*:=!"
if defined line (
set "line=!line:%search%=%replace%!"
set "line=!line:</=!"
)
(echo(!line!)
endlocal
)
) > "%newfile%"
endlocal
exit /b
Download something called "FART"
then include it in the folder of the batch then do a bat with this code
"#echo off
FART -i -r "12739*" "&" " AND " "
You need to escape the & Ampersand using the ^ character.
#echo off
setlocal
setlocal enabledelayedexpansion
set "search=^&"
set "replace= AND "
set "textfile=12739*"
set "newfile=Output.txt"
(
for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
set "line=!line:%search%=%replace%!"
echo(!line!
)
) > "%newfile%"
del %textfile%
rename %newfile% %textfile%
endlocal

Batch file to Replace underscore(_)from header of text file

I got a Pipe(|) separated file new.txt. I want to create a batch file which replaces underscore characters from new.txt keeping the data intact. I have created a batch which replaces underscore even from data. Please help.
new.txt contains header
Transaction_Type|Spend_Source_System|Event_ID|Expense_ID
Batch code I have written is
#echo off &setlocal
set "search=_"
set "replace= "
set "textfile=D:\test.txt"
set "newfile=D:\test2.txt"
(for /f %%i in ('findstr "^" "%textfile%"') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
))>"%newfile%"
type "%newfile%"
(for /f "DELIMS=" %%i in ('findstr "^" "%textfile%"') do (
should fix your problem.
Ah - it would appear they you may wish to replace the underscores only in the header line.
set "search=_"
set "replace= "
set "textfile=D:\test.txt"
set "newfile=D:\test2.txt"
SET header=Y
(for /f "delims=" %%i in ('findstr "^" "%textfile%"') do (
IF DEFINED header (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
ENDLOCAL
SET "header="
) ELSE (ECHO(%%i)
))>"%newfile%"

Resources