Find and replace string using for / f with if statement and variables

I wrote a batch file that I want to overwrite lines with lines from another .txt file.

it currently completely copies the new File.txt file, but does not replace the lines with the lines from the OldFile.txt file.

Example lines in File.txt:

...

# Password
Pword =

# AccountName
Account =

# TownName
City =

# Postcode
Index =

# LocationChangedDate
LocationChanged =

An example of the lines in the OldFile.txt file I want to replace from:

...

# Password
Pword = abc

# AccountName
Score = 123

# TownName
City = LDN

# Postcode
Postal Code = WS77TP

# LocationChangedDate
LocationChanged = 01/01/2015

Can someone point me in the right direction or explain where I 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 
+5
source share
4 answers

I think I finally understood ...

What does he do:

  • It scans the contents of OldFile.txt, looking for markers, if it is found that they are stored in environment variables that will be used in the socket step (for example, for the marker _PWD (variable), which has the value Pword= , it will create the variable _PWDCONTENTS with the contents Pword=ABC ).
  • It scans the contents of File.txt, looking for the same markers, if one marker is found, the corresponding CONTENTS variable is unloaded into OutFile.txt, otherwise the original string. Since this happens in the inner for loop, I had to add some extra logic ( _WROTE var) to avoid writing the same lines more than once.

Notes:

  • It is assumed (well, except that it should) be “customizable” (the code is complex, it moves to meta :) if you want), which means that if there are changes between the markers, the code should not change (well, there would be code changes, but not in the functional part only in the definitions of variables). Let me read more:

    • If you no longer need to replace the string Town= , all you have to do is remove _TOWN from _ALL : set _ALL=_PWD _ACCT _POST _LOC .
    • The opposite: if you want to add some other tag (let it be the name Name), you need 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 did not focus on performance, so it could work slowly. In any case, I tried with minimal restriction of access to the disk (which were very slow) (one example is when 2 for executes a loop that iterates on the contents of the file - provided that each iteration takes access to the disk, this maybe not so true, but Win has I / O buffering - it's external).

  • I “commented out” the last line in the file to avoid overwriting the original file. If this behavior is necessary, simply remove 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 the @StevoStephenson clause (as part of the question snippet), I replaced (2) the outer for loop with ('findstr /n "^^" !_INFILE!') To include empty lines, so the third remark no longer applies (deletion). Small changes have also been made to allow files containing SPACE s in their paths.

+3
source

This is not ideal, but it may be good 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 left the deletion and renaming for you at the end.

+1
source

Perhaps 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 

In for /f "delims=" %%i in ('findstr %str_search% %copyfile%') do set str_replace=%%i you write a string with a variable that has the necessary information for str_replace. After that, the program calls the built-in function find-and-replace-function ( :far ), which wordlessly stole from the Batch script to find and replace the line in the text file without creating an additional output file for storing the modified file. This function finds the string "Pword" and replaces it with a string search in the old file.

Caution: This will not solve your problem completely, since your new file should be like this.

 #Password Pword 

therefore, if you lose = , it works differently, if not. Hope this helps you solve your problem.

0
source

This solution should be much faster than other solutions.
It will also save blank lines and lines containing ! and ^ .

He needs only one findstr call to collect old values ​​for all words.
The second findstr defines all the lines (by line number) in the infile that need updating.

 @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!" 
0
source

All Articles