Bat file that takes specific variables on specific lines from texts - batch-file

I need to create a batch file that searches through 2 texts. Captures a line of text in a variable (that contains at least one of 3 strings, but doesn't contain forth string) and its line number.
Searches through the second text and captures in another variable the line of text that exists on the line-number of the first variable.
I need to use the two lines-of-text (variable) after that as well.
I kind of managed through the first text reading, but not sure what I'm doing wrong in the second one:
#echo off
set "found="
for /f "tokens=1,* delims=[]" %%a in (' find /n /v "" ^< "%LocalDir%\list.txt" ') do (
echo "%%b"|findstr /i /c:"one two small" /c:"one two birds" /c:"one two strings" >nul && set found=1
if defined found echo "%%b"|findstr /v /c:"one two small red apples" >nul || set "found="
if defined found (
echo %%a found
#echo off & setLocal EnableDelayedExpansion
set var=%%b
set Line_num=%%a
endlocal
) else (
echo %%a NOT FOUND
)
set "found="
)
REM part2--------------------
for /f "delims=" %%d in (list1.txt) do (
set FullVersion=%%d
#echo off & setLocal EnableDelayedExpansion
for /f "tokens=1* delims=" %%e in ("%%d") do (
if !Line_num!==%%e
set var2=!FullVersion!
echo !var2!
)
)
endlocal
echo %var%
echo %var2%
Any help will be appreciated.
here is what I end up with as solution:
for /f "tokens=1,* delims=[]" %%a in (' find /n /v "" ^< "%LocalDir%\software_list.txt" ') do (
echo "%%b"|findstr /i /c:"Micro Focus Enterprise " /c:"Micro Focus Visual" /c:"Micro Focus COBOL" >nul && set found=1
if defined found echo "%%b"|findstr /v /c:"Micro Focus Enterprise Server for .NET" >nul || set "found="
if defined found (set LineNumber=%%a&set ProductName=%%b)
REM else (echo Main Micro Focus product NOT FOUND. Nothing to do. Exit.&exit /b)
set "found="
)
find "2." temp1.txt > temp3.txt
for /f "tokens=2,3 delims==" %%c in (temp3.txt) do (echo %%c >> %LocalDir%\software_list1.txt)
for /f "tokens=1*delims=[]" %%a in (' find /n /v "" ^< "software_list1.txt" ') do IF %%a==%LineNumber% SET ProductVersion=%%b
REM ECHO %LineNumber%
REM ECHO %ProductName%
REM ECHO %ProductVersion%
set ProductName=%ProductName:"=%
set ProductName=%ProductName: =%
set ProductVersion=%ProductVersion:"=%
set ProductVersion=%ProductVersion: =%
set out_file_name=%ProductName%_%ProductVersion%_%COMPUTER_NAME%
REM echo %out_file_name:"=%
Thanks a lot to everyone.

I see some problems in your code:
This block makes no sense, as it set variables in a new setlocal context and after the endlocal the variables are lost.
#echo off & setLocal EnableDelayedExpansion
set var=%%b
set Line_num=%%a
endlocal
In the second block you open a setlocal context for each iteration, that will result in a overflow error.
And the endlocal after the Part2 seems also to be contraproductive.
The line if !Line_num!==%%e creates always a syntax error
Btw. Why do you use #echo off inside your code? The frist one at the batch start should be enough.
You should only use one setlocal EnableDelayedExpansion at the beginning of the script.
You should only use DelayedExpansion toggling, if you have problems with exclamation marks.
You could use some echo's to see what happens, like
for /f "tokens=1* delims=" %%e in ("%%d") do (
echo Compare: !Line_num!==%%e
if !Line_num!==%%e set var2=!FullVersion!
echo !var2!
)

#echo off
set "found="
for /f "tokens=1*delims=[]" %%a in (
' find /n /v "one two small red apples" ^< "%LocalDir%\list.txt" ') do (
echo "%%b"|findstr /i /c:"one two small" /c:"one two birds" /c:"one two strings" >NUL
IF NOT ERRORLEVEL 1 SET lnbr=%%a&SET ltext=%%b
)
for /f "tokens=1*delims=[]" %%a in (' find /n /v "" ^< "list1.txt" ') do IF %%a==%lnbr% SET L1txt=%%b
ECHO(line number %lnbr%
ECHO(from LIST %ltext%
ECHO(from LIST1 %L1txt%
This should do what you want - if I understand correctly. Much better to show your data and an example of required output. Trying to fix code that DOESN'T do something undefined is frustrating.

#echo off
rem I need to create a batch file that searches through 2 text FILEs.
rem Captures a line of text in a variable (that contains at least one of 3
rem strings, but doesn't contain forth string) and its line number.
set Line_num=
for /F "tokens=1* delims=:" %%a in (
'findstr /N /I /C:"one two small" /C:"one two birds" /C:"one two strings" "%LocalDir%\list.txt"
^| findstr /V /C:"one two small red apples"' ) do (
echo %%a found
set var=%%b
set Line_num=%%a
)
REM part2--------------------
if defined Line_num (
rem Searches through the second text and captures in another variable
rem the line of text that exists on the line-number of the first variable.
for /F "tokens=1* delims=:" %%d in ('findstr /N "^" list1.txt') do (
if %Line_num% == %%d (
set var2=%%e
echo %%e
)
)
)
echo %var%
echo %var2%

Related

IS this possible to modify multiple variable from same file using a .batch file without effecting other things like space, special char?

I have a file rev.ini having multiple variable to update:
s1=10
s2=20
s3=30
Here I am using separate loop for finding string in a file. there are 3 times loop are running for same file. Is it possible to find these three string in same loop?
#Echo Off
cd /d D:\xyz
setlocal enabledelayedexpansion
set s1=10
set s2=11
set s3=12
set "file=rev.ini"
for /F "tokens=1,* delims==" %%i in ('findstr "s1= " rev.ini') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set sequence=%s1%
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
for /F "tokens=1,* delims==" %%i in ('findstr "s2= " rev.ini') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set sequence=%s2%
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
for /F "tokens=1,* delims==" %%i in ('findstr "s3= " rev.ini') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set sequence=%s3%
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
Goto :EOF
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
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%\q74276740.txt"
SET "outfile=outfile.txt"
set "s1=10"
set "s2=11"
set "s3=12"
REM (
FOR /f "usebackqtokens=1*delims==" %%b IN ("%filename1%") DO (
SET "#keep=Y"
FOR /f "tokens=1*delims==" %%u IN ('set') DO (IF /i "%%b"=="%%u" SET "#keep="&ECHO %%b=%%v)
IF DEFINED #keep IF "%%c"=="" (ECHO %%b) ELSE (ECHO %%b=%%c)
)
REM )>"%outfile%"
GOTO :EOF
Always verify against a test directory before applying to real data.
Note that if the filename does not contain separators like spaces, then both usebackq and the quotes around %filename1% can be omitted.
Simply read each line. If the line contains = and the part before the = contains any variablename in the environment (I made it case-insensitive with /i) then generate a line using the matching value. If #keep remains set after the for..%%u has been executed, then there is no match, so either reproduce the original x=y or the original line, if it had no =.
The output file can be generated by removing the rem before the ( and ).
The output file must be different from the input file, and should be moved over the input file when the batch finishes (not shown)
--- After comment ---
So, if you follow the instructions provided in the last two paragraphs, you get
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
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%\q74276740.txt"
SET "outfile=outfile.txt"
set "s1=10"
set "s2=11"
set "s3=12"
(
FOR /f "usebackqtokens=1*delims==" %%b IN ("%filename1%") DO (
SET "#keep=Y"
FOR /f "tokens=1*delims==" %%u IN ('set') DO (IF /i "%%b"=="%%u" SET "#keep="&ECHO %%b=%%v)
IF DEFINED #keep IF "%%c"=="" (ECHO %%b) ELSE (ECHO %%b=%%c)
)
)>"%outfile%"
move "%outfile%" "%filename1%"
GOTO :EOF
== revision of processing section in light of new requirement to retain empty lines ==
REM (
FOR /f "tokens=1,2*delims=:=" %%g IN ('findstr /n ^^^^ "%filename1%"') DO IF "%%h"=="" (ECHO.) ELSE (
SET "#keep=Y"
FOR /f "tokens=1*delims==" %%u IN ('set') DO (IF /i "%%h"=="%%u" SET "#keep="&ECHO %%h=%%v)
IF DEFINED #keep IF "%%i"=="" (ECHO %%h) ELSE (ECHO %%h=%%i)
)
REM )>"%outfile%"
Once again, the rem keywords need to be removed to output to the nominated file.
The changes simply feed the file through a findstr command which produces a listing of the file with a prefix of linenumber:. The extra : in the delims causes the line number to be parsed to %%g. I've changed the metavariable letters because three are required for the processing, and I prefer to not use letters that are also modifiers.
If findstr produces only a line number then it was a blank line, so %%h will be empty and we simply produce an empty line, otherwise, processing as before.

Remove everything after the last occurrence of selected character in the first line

Let's say we have a variable that contains multiple lines of text containing full file names, such as
C:\Program Files\gs\gs9.26\Resource\CMap\Adobe-Japan2-0
C:\Program Files\Inkscape\share\poppler\cMap\Adobe-Japan2\Adobe-Japan2-0
...and this multi-line text is assigned to the variable var.
In Windows/DOS command prompt (not PowerShell), without a use of any external tools, how can I remove everything after the last occurrence of the character \ in the first line, i.e. for the above example to get only
C:\Program Files\gs\gs9.26\Resource\CMap\
Here is a part of the code I use:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
for /f %%x in ('copy /z "%~dpf0" nul') do set "CR=%%x"
(set LF=^
%==%
)
set TAB= "
set "TAB=%TAB:"=%
net session >nul 2>&1
if !errorLevel! NEQ 0 (
echo ERROR: Use "Run as administrator" to execute this file.!LF!
pause
exit /b 1
)
<nul set/p"=Analyzing... "
set "nil= "
for /l %%i in (2,1,80) do call set "nil=%%nil%%%nil%"
set "STDOUT="
set "STDERR="
for /f "delims=" %%E in ('
2^>^&1 ^(^
for /f "delims=" %%O in ^('^
where /R "%programfiles%" "*adobe*.*"
^^^^^^^| findstr /i /n /r "japan2"^
'^) do #^(^
echo ^^^^^^^|%%O^
^)^
^) ^| findstr /n /r "^"
') do (
set "LINE=%%E"
set "LINE=!LINE:*:=!"
if "!LINE:~,1!" == "|" (
set "STDOUT=!STDOUT!!LINE:*:=!!LF!"
) else (
set "STDERR=!STDERR!!LINE!!LF!"
)
)
The original code created trailing whitespace to each path it found. I modified the code to get rid of this.
The paths had to be double quote as they contain whitespace in the path as well. The variable !STDOUT! with therefore have the following format:
"C:\Program Files\gs\gs9.26\Resource\CMap\Adobe-Japan2-0"
"C:\Program Files\Inkscape\share\poppler\cMap\Adobe-Japan2\Adobe-Japan2-0"
You mentioned that this is only part of the code, so you need to make sure that everything else works as expected.
Note however that you need to copy this part of the code "exactly" as is as I have amended a few parts of it, if you don't, it will not work as expected.
Lastly, I have to add. I am not sure of the reason this code was designed like this, I cannot see any specific reason, based on the current scenario.
This code is a bit of an overkill for now, unless you can provide a specific reason. I do not see any reason why the variable cannot be set without the line feeds.
Anyway, here it is:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
for /f %%x in ('copy /z "%~dpf0" nul') do set "CR=%%x"
(set LF=^
%==%
)
set TAB= "
set "TAB=%TAB:"=%
net session >nul 2>&1
if !errorLevel! NEQ 0 (
echo ERROR: Use "Run as administrator" to execute this file.!LF!
pause
exit /b 1
)
<nul set/p"=Analyzing... "
echo(
set "nil= "
for /l %%i in (2,1,80) do call set "nil=%%nil%%%nil%"
set "STDOUT="
set "STDERR="
for /f "delims=" %%E in ('
2^>^&1 ^(^
for /f "delims=" %%O in ^('^
where /R "%programfiles%" "*adobe*.*"
^^^^^^^| findstr /i /n /r "japan2"^
'^) do #^(^
echo ^^^^^^^|%%O^
^)^
^) ^| findstr /n /r "^"
') do (
set "LINE=%%E"
set "LINE=!LINE:*:=!"
set "LINE=!LINE: =!"
if "!LINE:~,1!" == "|" (
set STDOUT=!STDOUT!"!LINE:*:=!"!LF!
) else (
set "STDERR=!STDERR!!LINE!!LF!"
)
)
for %%i in (!STDOUT!) do set "dir=%%~dpi" & goto cont:
:cont
echo !dir!
The main changes in the code you provided are here:
set "LINE=!LINE: =!" :: Removed the two trailing whitespaces
if "!LINE:~,1!" == "|" (
set STDOUT=!STDOUT!"!LINE:*:=!"!LF! :: Double quote the line so we can format them correctly.
This will allow proper usage of the strings in a list form.
Then, my code added. This sets a pth variable using drive and path to file. We then strip the trailing \ to allow the next %%~dpa to assign the drive and path to the point where you wanted it.
for %%i in (!STDOUT!) do set "dir=%%~dpi" & goto cont:
:cont
echo !dir!
The result will then be:
C:\Program Files\gs\gs9.26\Resource\CMap\
Finally, if you want to see that my part of the code does in fact remove the parts from path as you wanted, you can do this in my code section:
for %%i in (!STDOUT!) do (
echo %%~dpi
)
Or if you want to set each of them to a dir[n] to resemble an array, then place this in my code section:
set _n=1
for %%i in (!STDOUT!) do (
set "dir[!_n!]=%%~dpi"
set /a _n+=1
)
for /l %%n in (0,1,!_n!) do echo(!dir[%%n]!
set dir

How to change parametes in notes.ini file with batch file

I have a notes.ini file with the following starting line:
[Notes]
Directory=c:\lotus\notes\data
I would like to change the "Directory=" parameter to Directory = D:\Users\fr21466\AppData\Roaming\notes
I´m trying this code:
#echo off
set file=c:\lotus\notes\notes.ini
set newline=Directory=%appdata%\notes
set insertline=2
set output=%appdata%\notes\notes.ini
(for /f "tokens=1* delims=[]" %%a in ('find /n /v "##" ^< "%file%"') do (
if "%%~a"=="%insertline%" (
echo %newline%
REM ECHO.%%b
) ELSE (
echo.%%b
)
)) > %output%
But the output file is generating this:
It is generating the file, but cutting the symbol: "[" in the first column
Notes]
Directory=D:\Users\fr21466\AppData\Roaming\notes
Can someone please help me to solve this?
Thank You!
Try ini.bat (the second one, under the Update section).
copy "c:\lotus\notes\notes.ini" "%appdata%\notes"
ini.bat /s Notes /i Directory /v "%appdata%\notes" "%appdata%\notes\notes.ini"
To fix your current script, try replacing find with findstr and delims=:. The /N option with findstr prefaces lines with nn: rather than [nn], so your ini sections won't be clobbered when their surrounding brackets are treated as a successive delimiter.
#echo off & setlocal
set "file=c:\lotus\notes\notes.ini"
set "newline=Directory=%appdata%\notes"
set "insertline=2"
set "output=%appdata%\notes\notes.ini"
(for /f "tokens=1* delims=:" %%a in ('findstr /n /v "##" ^< "%file%"') do (
if "%%~a"=="%insertline%" (
echo(%newline%
REM ECHO.%%b
) ELSE (
echo(%%b
)
)) > "%output%"
#ECHO Off
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q45036613.txt"
SET "outfile=%destdir%\outfile.txt"
set file=%filename1%
set newline=Directory=%appdata%\notes
REM set insertline=2
set output=%outfile%
SET "notessection="
(FOR /f "delims=" %%x IN (%file%) DO (
for /f "tokens=1* delims==" %%a in ("%%x") do (
IF NOT DEFINED notessection ECHO(%%x
IF DEFINED notessection (
IF /i "%%a"=="Directory" (
ECHO(%newline%
SET "notessection="
) ELSE (
ECHO(%%x
)
)
IF /i "%%a"=="[Notes]" SET "notessection=Y"
)
)) > %output%
GOTO :EOF
I used a file named q45036613.txt containing your data + more for my testing. I've also adjusted the paths to suit my system.
This version doesn't rely on the position of the directory entry; it looks for the [Notes] line and adjusts the directory entry that follows by using the characteristic that if defined interprets the run-time value of a variable. Hence, wait for [Notes] then wait for directory
To fix it remove [ from line 6

batch command to search and output the content between the first and last occurrence of the search key

I have a log file and I have a keyword to search the log file. Now I have to extract all the contents from that log file between the first and the last occurrence of the search key. ie everything in between the first and last occurrence. the findstr command only lists out the lines that are having the search key and not the other contents in between. I need batch commands to do that.
eg.
log.txt
[mave123]sddasnsdaskdasddansnmdmsmdasdasda
[mave123]dfdfdf
fsffasf
safaaf
fasfssfdfdsfdsf
[mave123]dfsfsdfsdfssdfssfd
[mave124]rdfsdfsfsfsf
[mave124]dfdfsdfsfsdfs
now the "findstr mave123 log.txt" will return as below
[mave123]sddasnsdaskdasddansnmdmsmdasdasda
[mave123]dfdfdf
[mave123]dfsfsdfsdfssdfssfd
but I want all the contents between the fist and last occurrences of mave123. ie like this. Can you please help?
[mave123]sddasnsdaskdasddansnmdmsmdasdasda
[mave123]dfdfdf
fsffasf
safaaf
fasfssfdfdsfdsf
[mave123]dfsfsdfsdfssdfssfd
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q35976147.txt"
SET "outfile=%destdir%\outfile.txt"
SET "target=%~1"
IF NOT DEFINED target GOTO :eof
SET "startline="
FOR /f "delims=:" %%a IN ('findstr /N /L /c:"%target%" "%filename1%" ') DO (
IF NOT DEFINED startline SET /a startline=%%a
SET /a endline=%%a
)
IF NOT DEFINED startline ECHO NOT found&GOTO :EOF
(
FOR /f "tokens=1*delims=:" %%a IN ('findstr /N /r "." "%filename1%" ') DO (
IF %%a geq %startline% (
IF %%a leq %endline% (ECHO %%b) ELSE (GOTO nextstep)
)
)
)>"%outfile%"
:nextstep
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances.
I used a file named q35976147.txt containing your data for my testing.
Produces the file defined as %outfile%
The first for prefixes each line number matching the target string with linenumber: then assigns the first line number found to startline and surprisingly the last to endline
The second for repeats the operation, this time outputting the lines in the range selected.
This will suppress any leading : on lines. I haven't tested blank lines.
Revision for "all matching files"
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "target=%~1"
IF NOT DEFINED target GOTO :eof
FOR %%j IN ("%sourcedir%\log_*.txt".) DO (
ECHO %%j
SET "startline="
FOR /f "delims=:" %%a IN ('findstr /N /L /c:"%target%" "%%j" ') DO (
IF NOT DEFINED startline SET /a startline=%%a
SET /a endline=%%a
)
IF DEFINED startline (
SETLOCAL enabledelayedexpansion
(
FOR /f "tokens=1*delims=:" %%a IN ('findstr /N /r "." "%%j" ') DO (
IF %%a geq !startline! IF %%a leq !endline! (ECHO %%b)
)
ENDLOCAL
)>"%destdir%\%%~nj.out"
) ELSE (
ECHO "%target%" NOT found IN %%j
)
)
GOTO :EOF
Here, %%j receives the name of the file to be processed. The destination file is constructed from the destination directory name, the name part of the source file (%%~nj) and .out A SETLOCAL/ENDLOCAL bracket is established to allow the run-time values of startline and endline to be accessed.
always best to state the complete problem as it often radically changes the approach.

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!"

Resources