使用for/f和if语句和变量查找和替换字符串

Ste*_*son 5 batch-file find-replace

我写了一个批处理文件,我想用另一个.txt文件中的字符串覆盖键字符串.

目前它完全复制新的File.txt文件,但不会用OldFile.txt文件中的字符串替换字符串.

File.txt文件中的字符串示例:

...

#密码
PWORD =

#AccountName
Account =

#TownName
Town =

#Postcode
Postcode =

#LocationChangedDate
LocationChanged =

我想要替换的OldFile.txt文件中的字符串示例:

...

#密码
PWORD = ABC

#AccountName
帐户= 123

#TownName
Town = LDN

#邮编
邮编= WS77TP

#LocationChangedDate
LocationChanged = 01/01/2015

有人可以指出我正确的方向或解释我在哪里犯了错误?

@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
Run Code Online (Sandbox Code Playgroud)

Cri*_*ati 2

我想我终于明白了...

它能做什么:

  • 它会遍历OldFile.txt内容,搜索标记,如果找到,它们将存储到环境变量中以在嵌套步骤中使用(例如,对于_PWD值为 的标记(变量)Pword=,它将创建一个_PWDCONTENTS内容为Pword=ABC)。
  • 它会遍历File.txt内容,搜索相同的标记,如果找到一个标记,则相应的CONTENTS变量将转储到OutFile.txt中,否则转储到原始行中。因为这种情况发生在内部for循环中,所以我必须添加一些额外的逻辑(_WROTEvar)以避免多次写入相同的行。

注意事项

  • 它应该(嗯,除了做它应该做的事情之外)是“可配置的”(代码很复杂,如果你愿意的话,它正在走向:)),这意味着如果标记之间有变化,代码不应该改变(嗯,会有代码更改,但不是在功能部分,仅在变量定义中)。让我详细说明一下:

    • 如果您不再需要替换该Town=字符串,那么您所要做的就是_TOWN_ALL:中删除set _ALL=_PWD _ACCT _POST _LOC
    • 相反:如果您想添加一些其他标签(我们称之为Name),您必须创建一个新的环境变量:set _NAME=Name=并将其添加到_ALL: set _ALL=_PWD _ACCT _TOWN _POST _LOC _NAME
  • 作为间接后果,我没有关注性能,因此它可能运行缓慢。无论如何,我试图将磁盘访问(速度非常慢)保持在最低限度(一个例子是当有 2 个for循环迭代文件内容时 - 假设每次迭代都需要一次磁盘访问;这可能不是真的,并且Win有 IO 缓冲 - 这是外部缓冲)。

  • 我“注释”了文件中的最后一行,以避免覆盖原始文件。如果需要该行为,只需删除rem开头的 即可。

这是批处理代码:

@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%
Run Code Online (Sandbox Code Playgroud)

@EDIT0:使用@StevoStephenson建议(作为问题片段的一部分),我将(第二个)外部for循环替换为('findstr /n "^^" !_INFILE!')以包含空行,因此第三个注释不再适用(删除)。还做了一些小更改以允许文件在其路径中包含SPACE