Change file content using batch - batch-file

So I have this going and I need a little help to improve it
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
cd /d "%~dp0"
:: Significant part of string
set "replacemain="appi": "
#For %%G In ("%~dp0Originals") Do Set "sourcedir=%%~fG"
#For %%G In ("%~dp0Ready") Do Set "destdir=%%~fG"
FOR /f "delims=" %%q IN ('dir /b /s /a-d "%sourcedir%\(*)*.txt"') DO (
rem calculate new destination directory
SET "newdest=%%~dpq"
SET "newdest=!newdest:%sourcedir%=%destdir%!"
SET "newdest=!newdest:~0,-1!"
MD "!newdest!" 2>nul
(
FOR /f "tokens=1 delims=()" %%j IN ("%%~nxq") DO (
rem %%j now has sequence number
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:appi=!" CALL :subs %%j
echo(!line!
)
)
)>"!newdest!\%%~nxq"
)
GOTO :eof
:: substitute
:subs
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%replacemain%%%s=%replacemain%!"
IF "%original%" neq "%line%" goto subs
set "line=!line:%replacemain%=%replacemain%%1!"
GOTO :eof
This is designed to read anything in the filename in closed by ( )
Main Folder
|
+-\Orignal
|--| + - (100) Craft.txt
|--------------"appi": 4748483,
+-\Ready
|--| + - (100) Craft.txt
|--------------"appi": 100,
My script is based on 1 code editing and now I have been trying to change it to multiple code editing
As you can see here, this is set for one code I would like to change it to a type of dictionary
set "replacemain="appi": "
My goal
replace=replacemain = ("appi":
"code":
"gedt":)
set "replace"
if defined line IF "%%b" neq "!line:replace=!" CALL :subs %%j
echo(!line!
Could this be possible, and all codes will change to match the file name in the (?)
Also is there a way to increase the speed of the script
Thank you
This is how it looks inside my txt file
BEFORE
(100) filename.txt
|----"appi": 4748483,
"code": 415241,
"gedt": 458421,
AFTER
(100) filename.txt
|----"appi": 100,
"code": 100,
"gedt": 100,

Related

How to add a goto to a for loop

I am working on a script that edits files and I am building a choice goto menu.
The script itself works fine, it reads from a file name that has ( ) in it. So my files are saved like this (1) filename.txt, (2) filename.txt ....(100) filename.txt
the content of the file has "times": 125489, saved in it, the script removes the 100 from the file name and does this "times": 100,
This is a small part of my content for my txt files it has a 4 indent space per line I believe the format is Json
"aidr": 3.58,
"nlpr": 0.5,
"tafr": 0.5,
"titp": 0.5,
"trld": 0.0,
"tssp": 0.5,
"tssr": 0.5,
"ttup": 0.5,
"ttpp": 0.5,
"times": 125,
"Stamp": 125,
"ppiid": 649,
"otiid": 649,
"apcid": 9,
"orcid": 9,
"jpcns": 0,
"agpns": 0,
"opcns": 0,
"rppns": 0,
I recently found that when I merged all my single scripts together it slows down dramatically. Before the script processed 500 .txt files in 1 minute but now it takes 30 minutes.
My goal is to find a way to bring back the speed of this script.
I heard and read that adding a goto before and after the loop could make the script fast again.
#echo off
:Menu
ECHO ################################################################
echo.
ECHO 1 - Script 1
ECHO 2 - Script 2
ECHO 3 - Script 3
ECHO 4 - Script 4
ECHO 5 - Script 5
ECHO 100 - Script 100
echo.
set pass=
:: the choice command
set /p Mchoice=Make Your Choice:
::goto choices
goto=:%Mchoice%
goto %goto%
:1
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
set "ToReplace1="times": "
SET "sourcedir=New folder 1"
SET "destdir=New fodler 2"
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:times=!" CALL :Nums1 %%j
echo(!line!
)
)
)>"%destdir%\%%q"
)
GOTO :Menu
:Nums1
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace1%%%s=%ToReplace1%!"
IF "%original%" neq "%line%" goto Nums1
set "line=!line:%ToReplace1%=%ToReplace1%%1!"
GOTO :eof
:2
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
set "ToReplace2="Stamp": "
SET "sourcedir=New folder 1"
SET "destdir=New fodler 2"
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:Stamp=!" CALL :Nums2 %%j
echo(!line!
)
)
)>"%destdir%\%%q"
)
GOTO :Menu
:Nums2
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace2%%%s=%ToReplace2%!"
IF "%original%" neq "%line%" goto Nums1
set "line=!line:%ToReplace2%=%ToReplace2%%1!"
GOTO :eof
:15
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
cd /d "%~dp0"
set "ToReplace1="times": "
set "ToReplace2="Stamp": "
set "ToReplace3="jpcns": "
SET "sourcedir15=New folder 1"
SET "destdir15=New fodler 2"
FOR /f "delims=" %%q IN ('dir /b /s /a-d "%sourcedir15%\(*)*.txt"') DO (
SET "newdest=%%~dpq"
SET "newdest=!newdest:%sourcedir15%=%destdir15%!"
SET "newdest=!newdest:~0,-1!"
MD "!newdest!" 2>nul
(
FOR /f "tokens=1 delims=()" %%j IN ("%%~nxq") DO (
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%%q"') do (
set "line=%%b"
if defined line IF "%%b" neq "!line:times=!" CALL :Nums15 %%j
if defined line IF "%%b" neq "!line:Stamp=!" CALL :Nums15 %%j
if defined line IF "%%b" neq "!line:jpcns=!" CALL :Nums15 %%j
echo(!line!
)
)
)>"!newdest!\%%~nxq"
)
GOTO :Menu
:Nums15
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace1%%%s=%ToReplace1%!"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace2%%%s=%ToReplace2%!"
FOR /L %%s IN (0,1,9) DO set "line=!line:%ToReplace3%%%s=%ToReplace3%!"
IF "%original%" neq "%line%" goto Nums15
set "line=!line:%ToReplace1%=%ToReplace1%%1!"
set "line=!line:%ToReplace2%=%ToReplace2%%1!"
set "line=!line:%ToReplace3%=%ToReplace3%%1!"
GOTO :eof
I've done a few exercises on this problem, but I've been unable to locate anything that might result in a 30:1 speed difference.
This version
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%b in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%c"
if defined line (
IF "%%c" equ "!line:times=!" (ECHO %%c) ELSE (
for /F "tokens=1* delims=:" %%v in ("%%c") do ECHO %%v: %%j,
)
) ELSE ECHO(
)
)
)>"%destdir%\%%q"
)
Seemed to be a little faster.
This:
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
SET "skipover="
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%sourcedir%\%%q"') do (
IF DEFINED skipover (ECHO(%%b
) ELSE (
set "line=%%b"
if defined line IF "%%b" neq "!line:times=!" SET "skipover=y"&CALL :Nums1 %%j
echo(!line!
)
)
)
)>"%destdir%\%%q"
)
uses a Boolean variable skipover to bypass some of the processing once the target line has been found and manipulated - but it actually seemed slower.
This
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
for /F "tokens=1* delims=:" %%b in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%c"
if defined line (
IF "%%c" equ "!line:times=!" (ECHO %%c) ELSE (
for /F "tokens=1* delims=:" %%v in ("%%c") do ECHO %%v: %%j,
)
) ELSE ECHO(
)
)
)>"%destdir%\%%q"
)
was consistently a little faster than the original - it avoids the subroutine call.
And this:
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO (
SET "skipover="
for /F "usebackqdelims=" %%e in ("%sourcedir%\%%q") do (
IF DEFINED skipover (ECHO/%%e
) ELSE (
set "line=%%e"
if defined line (
IF "%%e" equ "!line:times=!" (ECHO %%e
) ELSE (
SET "skipover=Y"
for /F "tokens=1* delims=:" %%v in ("%%e") do ECHO %%v: %%j,
)
) ELSE ECHO/
)
)
)
)>"%destdir%\%%q"
)
was consistently nearly twice as fast, using the skip-if-it's been-changed technique and avoiding findstr. It won't reproduce empty lines, though.
I also found that the position of the target in the source was signiificant. Using a 700-line version of the sample data, placing the target at the end was half-speed of placing it at the start of the file, so I was able to get nearly a 4:1 speed difference between the original and this last technique if the target was placed early in the source data (running 1,000 700-line files).
I presume that sub appeared in the original post by way of editing-out the irrelevant portions of the code, but it seemed to be reversed in sense, the way it was written...
--- based on version 3,
:: remove variables starting #
FOR /F "delims==" %%e In ('set # 2^>Nul') DO SET "%%e="
:: Read controls from file "%1"
FOR /f "usebackqtokens=1*" %%b IN ("%~1") DO (
SET "#%%b=%%c"
FINDSTR /x /i /L /c:":#%%b" <"%~f0" >NUL
IF ERRORLEVEL 1 ECHO LABEL ":#%%b" NOT found&SET "destdir="
)
IF NOT DEFINED destdir ECHO Required LABEL(s) NOT found &GOTO :eof
FOR /f "delims=" %%q IN ('dir /b /a-d "%sourcedir%\(*)*.txt"') DO (
(
rem %%q contains the name of the file to be processed
rem remove variables starting $
FOR /F "delims==" %%e In ('set $ 2^>Nul') DO SET "%%e="
rem extract filenumber if sourcefilename is (number)something
SET "filenumber="
FOR /f "tokens=1 delims=()" %%j IN ("%%q") DO SET "filenumber=%%j"
rem
rem now process the file
for /F "tokens=1* delims=:" %%b in ('findstr /N "^" "%sourcedir%\%%q"') do (
set "line=%%c"
if defined line (
rem if any #name is detected, take action
SET "processline=Y"
FOR /f "tokens=1,2delims=#=" %%u IN ('set #') DO IF DEFINED processline IF "%%c" neq "!line:%%u=!" (
SET "processline="
CALL :#%%u %%v
)
IF DEFINED processline ECHO %%c
) ELSE ECHO/
)
)>"%destdir%\%%q"
)
GOTO :eof
:#times
rem replace times value with filenumber
ECHO "times": %filenumber%,
GOTO :eof
:#titp
rem replace titp value with value read from file (%1)
ECHO "titp": %1,
GOTO :eof
:#tssp
rem put newz value before and zwen value after tssp value
ECHO "newz": whatever,
ECHO %line%
ECHO "zwen": revetahw,
GOTO :eof
:#trld
rem delete all trld values
GOTO :eof
:#tssr
rem replace the third and the fifth tssr value (I have multiples)
rem note that all $ variables are deleted FOR each file
SET /a $#tssr+=1
IF %$#tssr%==3 ECHO "tssr": thirdtime,&GOTO :eof
IF %$#tssr%==5 ECHO "tssr": fifthtime,&GOTO :eof
ECHO %line%
GOTO :eof
Using a control file contents
times #
titp jello
trld #
tssp #
tssr #
So - this is an attempt to obviate the repeated cloning of the file-processing logic.
First, I'm setting all variables that start # to nothing, un-defining them. That way, the remainder of the code knows that any variable starting # has not been inherited from elsewhere.
Next step : read the file to set up
#times=#
#titp=jello
#trld=#
#tssp=#
#tssr=#
The code then examines itself to make sure that subroutines :#times etc all exist and complains if they don't. destdir is simply a convenient non-empty variable used as a flag - we'll abort if the subroutines are missing, so no problem there.
Next - read the filenames. Obviously, the filemask may change depending on the selection made from the menu.
Then, for each file, kill all $ variables for the same reason as # but this time for each file to be processed.
Then set up variables to contain whatever data about the file is appropriate. Could be size, date, whatever - extract-parenethesised-number is shown. No harm in doing such things for all files, even if the data is not used for this particular menu selection.
Then process the file, detecting the keystrings from the # array. Call :#keystring if found, regurgitate line if not.
Each :# routine does what it does. A variety of possibilities is shown. Naturally, any particular routine could be controlled further by testing the selection made.
Setting the value assigned to #? to a value other than # will deliver that value to the :#? subroutine as parameters. Use them as you will - constants, whatever - just interpret the parameters delivered.
Naturally, you could set the # variables manually for particular menu selections instead of reading them from a file.
But - this is drifting way away from the timing problem - just adding more facilities (I'm a chronic implementor of bells and whistles) so I'd suggest to end discussion here.

Add numbers with same text together

I would like to create a batch file in which I can see what I have collected in a game.
The game saves this information in a .txt file.
The output would look like this.
70x Silver.
Back Pearl.
41x Copper.
Amethyst.
Amethyst.
12x Silver.
Back Pearl.
21x Copper.
5x Silver.
Back Pearl.
Back Pearl.
Amethyst.
What I want to do now, is to add the items with the same name together, like this:
128x Silver.
4x Back Pearl.
62x Copper.
3x Amethyst.
There are hundreds of items with different names, not just these 4.
Would that be possible?
Any help would be appreciated. Thanks!
Another one!
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%l in (test.txt) do for /F "tokens=1*" %%a in ("%%l") do (
set "first=%%a"
if "!first:~-1!" equ "x" (set /A "num=!first:~0,-1!") else set "num=0"
if !num! equ 0 (
set "rest=%%l"
set /A "count[!rest: =_!]+=1"
) else (
set "rest=%%b"
set /A "count[!rest: =_!]+=num"
)
)
(for /F "tokens=2* delims=[]=" %%a in ('set count[') do (
set "item=%%a"
if %%b equ 1 (
echo !item:_= !
) else (
echo %%bx !item:_= !
)
)) > summary.txt
#ECHO OFF
SETLOCAL
rem The following settings for the source directory and filename are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "filename1=%sourcedir%\q72672485.txt"
:: remove variables starting #
FOR /F "delims==" %%b In ('set # 2^>Nul') DO SET "%%b="
FOR /f "usebackqdelims=" %%b IN ("%filename1%") DO (
CALL :sub %%b
)
SETLOCAL ENABLEDELAYEDEXPANSION
(
FOR /F "tokens=1,2delims==" %%b In ('set # 2^>Nul') DO (
SET "line=%%cx%%b"
ECHO !line:#= !
)
)>summary.txt
endlocal
type summary.txt
GOTO :EOF
:sub
SET "quantity=%1"
SET "line=%*"
IF /i "%quantity:~-1%"=="x" (SET /a quantity=%quantity:~0,-1%&SET "line=%line:* =%") ELSE SET quantity=1
IF %quantity%==0 SET /a quantity=1&SET "line=%*"
SET /a #%line: =#%+=quantity
GOTO :eof
Different approach...
Would that be possible? - Yes.
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (t.txt) do (
set " z=%%a"
set " z=!z:x =#!"
set " z=!z: =_!"
for /f "tokens=1,2 delims=#" %%b in ("!z!") do (
if "%%c" == "" (
set "x=1"
set "y=%%b
) else (
set "x=%%b"
set "y=%%c"
)
set /a #!y!+=!x!
)
)
(for /f "tokens=1,2 delims=#=" %%a in ('set #') do (
set "x=%%a"
set "y=%%bx "
echo !y:~0,4! !x:_= !
))>summary.txt
Output with your example data (I hope, alphabetic sorting is ok for you):
3x Amethyst.
4x Back Pearl.
62x Copper.
87x Silver.
(your calculation of 120 silver might be a bit optimistic with the given input data)
This is a different approach that use a "file merge" method. The overall code is somewhat simpler than other methods...
#echo off
setlocal EnableDelayedExpansion
set "lineNum=0"
(for /F "tokens=1,2* delims=:x " %%a in ('(type test.txt ^& echo 0x^) ^| findstr /N "[0-9][0-9]*x"') do (
if !lineNum! lss %%a call :locateLine %%a
set "line=%%c"
set /A "count[!line: =_!]+=%%b"
)) < test.txt
set "count[="
(for /F "tokens=2* delims=[]=" %%a in ('set count[') do (
set "item=%%a"
if %%b equ 1 (echo !item:_= !) else echo %%bx !item:_= !
)) > summary.txt
goto :EOF
:locateLine num
set /A "lineNum+=1" & set /P "line=" & if errorlevel 1 exit /B
if %lineNum% lss %1 set /A "count[%line: =_%]+=1" & goto locateLine
exit /B
Another approach (splitting the file into items with and without quantity) (also fixing the Pollux Infusion issue in my first answer):
#echo off
setlocal enabledelayedexpansion
REM process lines without quantity:
for /f "delims=" %%a in ('type test.txt^|findstr /vrc:"[0123456789][0123456789]*x "') do call :count 1 "%%a"
REM process lines with quantity:
for /f "tokens=1*delims=x " %%a in ('type test.txt^|findstr /rc:"[0123456789][0123456789]*x "') do call :count %%a "%%b"
REM reformat:
(for /f "tokens=1,2 delims=#=" %%a in ('set #') do (
set "count=%%bx "
set "line=!count:~0,5!%%a" &REM including '1x'
if %%b==1 set "line= %%a" &REM supressing '1x'
echo !line:_= !
))>summary.txt
type summary.txt
goto :eof
:count
set item=%~2
set "item=%item: =_%"
set /a #%item% +=%1
Included both with and without 1x. Remove the line, you don't want.

how to remove a Negative using a txt editing batch script

I need a little help with this
I recently asked a different question on this same script
Now I have my scripted working for me and found a new issue
Here is my script
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
cd /d "%~dp0"
:: Significant part of string
set "params1="okhg": "
set "params2="tfed": "
set "params3="pkna": "
set "params4=txt": ""
#For %%G In ("%~dp0Preparing") Do Set "sourcedir=%%~fG"
#For %%G In ("%~dp0Ready") Do Set "destdir=%%~fG"
FOR /f "delims=" %%q IN ('dir /b /s /a-d "%sourcedir%\(*)*.txt"') DO (
rem calculate new destination directory
SET "newdest=%%~dpq"
SET "newdest=!newdest:%sourcedir%=%destdir%!"
SET "newdest=!newdest:~0,-1!"
MD "!newdest!" 2>nul
(
FOR /f "tokens=1 delims=()" %%j IN ("%%~nxq") DO (
rem %%j now has sequence number
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%%q"') do (
set "line=%%b"
for %%x in (%params1%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs1 %%j
for %%x in (%params2%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs2 %%j
for %%x in (%params3%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs3 %%j
for %%x in (%params4%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs4 %%j
echo(!line!
)
)
)>"!newdest!\%%~nxq"
)
GOTO :eof
:: substitute
:subs1
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params1%%%s=%params1%!"
IF "%original%" neq "%line%" goto subs1
set "line=!line:%params1%=%params1%%1!"
GOTO :eof
:subs2
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params2%%%s=%params2%!"
IF "%original%" neq "%line%" goto subs2
set "line=!line:%params2%=%params2%%1!"
GOTO :eof
:subs3
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params3%%%s=%params3%!"
IF "%original%" neq "%line%" goto subs3
set "line=!line:%params3%=%params3%%1!"
GOTO :eof
:subs4
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params4%%%s=%params4%!"
IF "%original%" neq "%line%" goto subs3
set "line=!line:%params4%=%params4%CITY%1!"
GOTO :eof
This is how it works
ORIGNAL FOLDER
+ ----- FOLDER 1
--------+ --(100) Filename.txt
-------------+ -- "okhg": 452587"
-------------+ -- "tfed": 6541"
-------------+ -- "pkna": -58452"
-------------+ -- "txt": ""
RESULTS FOLDER
+ ----- FOLDER 1
--------+ --(100) Filename.txt
-------------+ -- "okhg": 100"
-------------+ -- "tfed": 100"
-------------+ -- "pkna": 100-58452"
-------------+ -- "txt": "CITY100"
The issue I am coming across with is that this line has a negative
"pkna": -58452"
I have tested different ways to make the scripts remove the negative
if I leave it like this, I get this result
set "params3="pkna": "
"pkna": 100-58452"
if I do this, I get this result
set "params3="pkna": -"
"pkna": -100"
what I am looking for is this
"pkna": 100"
Thank you
Edit:
The question has been updated with an answer.
The code will "code" multiple row/lines in to a text file using its prefix name, or with a "more direct" coding.
If you do know a way to clean up the code feel free to post an answer to do so., I would like to leave a script that I can continue to add more codes if needed
Thank you for all the hard work you'll provide us with to make our scripts better
#ECHO Off
setlocal ENABLEDELAYEDEXPANSION
cd /d "%~dp0"
:: Significant part of string
set "params1="okhg": "
set "params2="tfed": "
set "params3="pkna": "
set "params4=txt": ""
#For %%G In ("%~dp0Preparing") Do Set "sourcedir=%%~fG"
#For %%G In ("%~dp0Ready") Do Set "destdir=%%~fG"
FOR /f "delims=" %%q IN ('dir /b /s /a-d "%sourcedir%\(*)*.txt"') DO (
rem calculate new destination directory
SET "newdest=%%~dpq"
SET "newdest=!newdest:%sourcedir%=%destdir%!"
SET "newdest=!newdest:~0,-1!"
MD "!newdest!" 2>nul
(
rem this will take the data in the filename enclosed in (!)
FOR /f "tokens=1 delims=()" %%j IN ("%%~nxq") DO (
rem this will replace any random codes found after : with 10
FOR /f "tokens=1 delims=()" %%k IN ("10") DO (
rem this will add any wording after this : and will take data enclosed in (!)
FOR /f "tokens=1 delims=()" %%l IN ("%%~nxq") DO (
rem %%j %%k %%l now has sequence number or pattern
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" "%%q"') do (
set "line=%%b"
rem in order to make each code work I gave them there own ::Substitute
for %%x in (%params1%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs1 %%j
for %%x in (%params2%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs2 %%j
for %%x in (%params3%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs3 %%k
for %%x in (%params4%) do if defined line IF "%%b" neq "!line:%%x=!" CALL :subs4 %%l
echo(!line!
)
)
)
)
)>"!newdest!\%%~nxq"
)
GOTO :eof
:: substitute
:subs1
SET "line=%line:-=%"
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params1%%%s=%params1%!"
IF "%original%" neq "%line%" goto subs1
set "line=!line:%params1%=%params1%%1!"
GOTO :eof
:subs2
SET "line=%line:-=%"
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params2%%%s=%params2%!"
IF "%original%" neq "%line%" goto subs2
set "line=!line:%params2%=%params2%%1!"
GOTO :eof
:subs3
SET "line=%line:-=%"
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params3%%%s=%params3%!"
IF "%original%" neq "%line%" goto subs3
set "line=!line:%params3%=%params3%%1!"
GOTO :eof
:subs4
SET "line=%line:-=%"
SET "original=%line%"
FOR /L %%s IN (0,1,9) DO set "line=!line:%params4%%%s=%params4%!"
IF "%original%" neq "%line%" goto subs3
set "line=!line:%params4%=%params4%City%1!"
GOTO :eof

Find & Replace string using for /f with if statement and variables

I have written a batch file which I want to overwrite key strings with strings from another .txt file.
currently it copies the new File.txt file perfectly but does not replace the strings with the strings from OldFile.txt file.
example of strings in File.txt file:
...
# Password
Pword=
# AccountName
Account=
# TownName
Town=
# Postcode
Postcode=
# LocationChangedDate
LocationChanged=
example of strings in OldFile.txt file I want to replace from:
...
# Password
Pword=ABC
# AccountName
Account=123
# TownName
Town=LDN
# Postcode
Postcode=WS77TP
# LocationChangedDate
LocationChanged=01/01/2015
Can someone please point me in the right direction or explain where I have made a mistake?
#echo off
setlocal disableDelayedExpansion
::Variables
set InputFile=F:\EXCHANGE\3\Machine\File.txt
set OutputFile=F:\EXCHANGE\3\File-New.txt
set CopyFile=F:\EXCHANGE\3\OldMachine\OldFile.txt
set _strFindPword=Pword=.*
for /F "delims=" %%A in ('findstr /x "Pword=.*" %CopyFile%') do set _strInsertPword=%%A
echo.%_strInsertPword%
set _strFindAccount=Account=.*
for /F "delims=" %%B in ('findstr /x "Account=.*" %CopyFile%') do set _strInsertAccount=%%B
echo.%_strInsertAccount%
set _strFindTown=Town=.*
for /F "delims=" %%C in ('findstr /x "Town=.*" %CopyFile%') do set _strInsertTown=%%C
echo.%_strInsertTown%
set _strFindLocationChanged=LocationChanged=.*
for /F "delims=" %%D in ('findstr /x "LocationChanged=.*" %CopyFile%') do set _strInsertLocationChanged=%%D
echo.%_strInsertLocationChanged%
set _strFindPostcode=Postcode=.*
for /F "delims=" %%E in ('findstr /x "Postcode=.*" %CopyFile%') do set _strInsertPostcode=%%E
echo.%_strInsertPostcode%
(
for /F "delims=" %%L in ('findstr /n "^" "%InputFile%"') do (
set "line=%%L"
setlocal EnableDelayedExpansion
set "line=!line:*:=!"
if "%%L" equ "_strFindPword" (echo.!_strInsertPword!) else (
if "%%L" equ "%_strFindAccount%" (echo.!_strInsertAccount!) else (
if "%%L" equ "%_strFindTown%" (echo.!_strInsertTown!) else (
if "%%L" equ "%_strFindLocationChanged%" (echo.!_strInsertLocationChanged!) else (
if "%%L" equ "%_strFindPostcode%" (echo.!_strInsertPostcode!) else (echo.!line!)
)
)
)
)
endlocal
)
) > "%OutputFile%"
del %InputFile%
ren %OutputFile% File.txt
pause
I think I finally got it...
What it does:
It goes through the OldFile.txt content, searching for markers, if found they are stored into environment variables to be used in the nest step (e.g. for _PWD marker (variable) which has a value of Pword=, it will create a _PWDCONTENTS variable with the content of Pword=ABC).
It goes through File.txt content, searching for the same markers, if one marker found, the corresponding CONTENTS variable is dumped in the OutFile.txt, else the original line. Because that happens in the inner for loop, I had to add some extra logic (the _WROTE var) to avoid writing the same lines more than once.
Notes:
It is supposed (well, besides doing what it's supposed to) to be "configurable" (the code is complicated, it's heading towards meta :) if you will), meaning that if there are changes between the markers the code shouldn't change (well there would be code changes, but not in the functional part only in variable definitions). Let me detail:
If you no longer need to replace the Town= string, then all you have to do is removing _TOWN from _ALL: set _ALL=_PWD _ACCT _POST _LOC.
The reverse: if you want to add some other tag (let's call it Name), you have to create a new environment variable: set _NAME=Name= and add it to _ALL: set _ALL=_PWD _ACCT _TOWN _POST _LOC _NAME.
As an indirect consequence, I didn't focus on performance, so it might run slow. Anyway I tried to keep the disk accesses (which are painfully slow) to a minimum (one example is when having 2 for loops the one that iterates on a file contents - assuming that each iteration takes a disk access; this might not be true, and Win has IO buffering - it's the outer one).
I "commented" out the last line in the file, to avoid overwriting the original file. If that behavior is needed, simply remove the rem at the beginning.
Here's the batch code:
#echo off
setlocal enabledelayedexpansion
set _INFILE="File.txt"
set _OUTFILE="NewFile.txt"
set _OLDFILE="OldFile.txt"
set _PWD=Pword=
set _ACCT=Account=
set _TOWN=Town=
set _POST=Postcode=
set _LOC=LocationChanged=
set _ALL=_PWD _ACCT _TOWN _POST _LOC
echo Parsing old file contents...
for /f "tokens=*" %%f in ('type !_OLDFILE!') do (
for %%g in (!_ALL!) do (
echo %%f | findstr /b /c:!%%g! 1>nul
if "!errorlevel!" equ "0" (
set %%gCONTENTS=%%f
)
)
)
copy nul %_OUTFILE%
echo Merging the old file contents into the new file...
set _WROTE=0
for /f "tokens=*" %%f in ('findstr /n "^^" !_INFILE!') do (
set _TMPVAR0=%%f
set _TMPVAR0=!_TMPVAR0:*:=!
for %%g in (!_ALL!) do (
echo !_TMPVAR0! | findstr /b /c:!%%g! 1>nul
if "!errorlevel!" equ "0" (
echo.!%%gCONTENTS!>>!_OUTFILE!
set _WROTE=1
)
)
if "!_WROTE!" equ "0" (
echo.!_TMPVAR0!>>!_OUTFILE!
) else (
set _WROTE=0
)
)
rem copy /-y %_OUTFILE% %_INFILE%
#EDIT0: Using #StevoStephenson suggestion (as part of the question snippet), I replaced the (2nd) outer for loop to ('findstr /n "^^" !_INFILE!') in order to include the empty lines, so the 3rd remark no longer applies (deleting). Also did some small changes to allow files that contain SPACE s in their paths.
Maybe it works like this
set CopyFile=oldfile.txt
set InputFile=newfile.txt
set str_search="Pword"
for /f "delims=" %%i in ('findstr %str_search% %copyfile%') do set str_replace=%%i
set str_replace="%str_replace%"
echo %str_search%
echo %str_replace%
pause
CALL :far %InputFile% %str_search% %str_replace%
EXIT /B 0
:far
setlocal enableextensions disabledelayedexpansion
set "search=%2"
set "replace=%3"
::remove quotes
set search=%search:"=%
set replace=%replace:"=%
echo %search%
echo %replace%
set "textFile=%1"
for /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
>>"%textFile%" echo(!line!
endlocal
)
EXIT /B 0
At for /f "delims=" %%i in ('findstr %str_search% %copyfile%') do set str_replace=%%i you write the line with the variable that has the needed info to str_replace.
After that you the program calls an embeded find-and-replace-function (:far) whitch i shemelessly stole from Batch script to find and replace a string in text file without creating an extra output file for storing the modified file
This function finds the string "Pword" and replaces it by the line find in the old file.
Attention:
This doesn't solve your problem completely since your new file has to be s.th like this.
#Password
Pword
so if you loose the = it works otherwise it doesn't. I hope this helps you with your problem.
It's not perfect but this may be okay for you:
#Echo Off
Setlocal EnableExtensions DisableDelayedExpansion
(Set InputFile=F:\EXCHANGE\3\Machine\File.txt)
(Set OutputFile=F:\EXCHANGE\3\File-New.txt)
(Set CopyFile=F:\EXCHANGE\3\OldMachine\OldFile.txt)
For /F "Delims=" %%I In (
'FindStr/B "Pword= Account= Town= LocationChanged= Postcode=" "%CopyFile%"'
) Do Set %%I
(For /F "Tokens=1-2* Delims=]=" %%I In ('Find /V /N ""^<"%InputFile%"') Do (
Echo(%%J|FindStr/B # || (If Defined %%J (Call Echo=%%J=%%%%J%%) Else (
If "%%J" NEq "" (Echo=%%J=%%K) Else (Echo=)))))>%OutputFile%
Timeout -1
EndLocal
Exit/B
I've left the delete and rename for you to add at the end.
This solution should be much faster than the other solutions.
It will also preserve empty lines and lines containing ! and ^.
It only needs one findstr call for collecting the old values for all words.
A second findstr determines all lines (by line number) in the infile which needs an update.
#echo off
setlocal EnableDelayedExpansion
set "_INFILE=File.txt"
set "_OUTFILE=NewFile.txt"
set "_OLDFILE="OldFile.txt"
set "_WORDS=Pword= Account= Town= Postcode= LocationChanged="
REM *** get all values for the key words
for /F "tokens=1,* delims==" %%L in ('findstr "!_WORDS!" "!_OLDFILE!"') do (
for /F %%S in ("%%L") do (
set "word[%%S]=%%M"
)
)
REM *** Find all lines which needs an update
set wordIdx=0
for /F "tokens=1,2,* delims=:= " %%1 in ('findstr /n "!_WORDS!" "!_INFILE!"') do (
set "lines[!wordIdx!].line=%%1"
set "lines[!wordIdx!].word=%%2"
set "replace=!word[%%2]!"
set "lines[!wordIdx!].replace=!replace!"
set /a wordIdx+=1
)
REM *** copy the infile to the outfile
REM *** Replace only the lines which are marked by line numbers
echo Parsing old file contents...
set nextWordIdx=0
set /a searchLine=lines[!nextWordIdx!].line
set lineNo=0
setlocal DisableDelayedExpansion
(
for /f "tokens=*" %%L in ('findstr /n "^" "%_INFILE%"') do (
set "line=%%L"
set /a lineNo+=1
setlocal EnableDelayedExpansion
set "line=!line:*:=!"
if !lineNo! equ !searchLine! (
(echo(!line!!lines[0].replace!)
set /a nextWordIdx+=1
for /F %%R in ("!nextWordIdx!") do (
endlocal
set /a nextWordIdx=%%R
set /a searchLine=lines[%%R].line
)
) ELSE (
(echo(!line!)
endlocal
)
)
) > "!_OUTFILE!"

How to get a Substring from list of file names

I want to develop the following logic
Read all files in a directory
Extract the first part of the filename – this will be the partner name
Extract anything after the first underscore- this will be filename
Eg: ZZTEST_123_abc_doc.txt  ZZTEST is partner. 123_abc_doc.txt is the filename.
Below is the code I developed
#echo off
setlocal ENABLEDELAYEDEXPANSION
Set Test_Dir=C:\Axway\projects\Cardinal\dosscript\test
cd %Test_Dir%
for /r %%a in (*.*) do (
Set "fname1=%%~nxa"
echo Filename is :!fname1!
for /f "tokens=1 delims=_" %%i in ("!fname1!") do (
Set "partner=%%i"
echo Partner is :!partner!
Set "str_tmp=!partner!_"
echo !str_tmp!
call :strlength length !str_tmp!
echo !length!
set fname=!fname1:~%length%!
echo !fname1:~%length%!
)
)
goto :eof
:strlength
setlocal enableextensions
set "#=%~2"
set length=0
:stringLengthLoop
if defined # (set "#=%#:~1%"&set /A length+=1&goto stringLengthLoop)
endlocal && set "%~1=%length%"
GOTO :EOF
But the result is
ID_ZZRoutingID_filename.txt
Filename is :ZZRoutingID_ZZRoutingID_filename1.txt
Partner is :ZZRoutingID
12
Result: ID_ZZRoutingID_filename1.txt
The result should be ZZRoutingID_filename1.txt but i am getting
ID_ZZRoutingID_filename1.txt.
Please help
The purpose of the length calculation is not clear to me, but I would suggest adding an asterisk following the 1 in your for /f "tokens=1 delims=_". You would then get the "filename" you were looking for through %%j.
I tested it like this:
#echo off
setlocal EnableDelayedExpansion
set source=D:\Program Files\Somewhere
cd %source%
for /r %%i in (*.*) do (
for /f "tokens=1* delims=_" %%j in ( "%%~nxi" ) do (
echo partner: %%j
echo name: %%k
)
)
endlocal
If you do not need to recurse through sub-directories:
#echo off
set source=D:\Program Files\Somewhere
for /f "tokens=1* delims=_" %%i in ( 'dir "%source%" /b /a-d' ) do (
echo partner: %%i
echo filename: %%j
)
dir /b /a-d retrieves the list of a directory's content except its sub-directories:
D:\Program Files\Somewhere>dir /b /a-d
ZZTEST_123_456.txt
ABCDEF_890_FFF.doc
FOOBAR_567_###.zzz

Resources