String .bat文件搜索和替换结构化文本文件中的字符串

String .bat文件搜索和替换结构化文本文件中的字符串,string,batch-file,replace,String,Batch File,Replace,我有一个文本文件,它使用[]对不同的子系统进行分组,然后在每个子组中包含项标志。以下是该文件的一个片段,您可以了解它的外观(请注意,每个子组可以有相同的项): 注意,上面的文件超过2000行。我想脚本需要一段时间才能执行。我也知道有一个更好的框架可以做到这一点,但在我们的应用程序中,我们需要它从闪存驱动器运行,并且能够插入到我们的仪器中,该仪器在没有.NET框架的情况下运行WinXP等 我想做的是使用.bat文件在文档中搜索特定子系统(即[DesiredSubsystem])和子系统中所需的项目

我有一个文本文件,它使用[]对不同的子系统进行分组,然后在每个子组中包含项标志。以下是该文件的一个片段,您可以了解它的外观(请注意,每个子组可以有相同的项):

注意,上面的文件超过2000行。我想脚本需要一段时间才能执行。我也知道有一个更好的框架可以做到这一点,但在我们的应用程序中,我们需要它从闪存驱动器运行,并且能够插入到我们的仪器中,该仪器在没有.NET框架的情况下运行WinXP等

我想做的是使用.bat文件在文档中搜索特定子系统(即[DesiredSubsystem])和子系统中所需的项目,然后修改项目数据。例如,在上面的文本中,我可能希望将PressureLevel Control子组中的对齐方式从789更改为12345

我理解使用bat文件无法有效替换/更新文本文件。我已经创建了一个函数来读取一个文件并将其写入一个新文件,现在我正在尝试开发一种干净的方法来识别行项目以及它们所在的子组,以便根据需要替换所需的文本

以下是我对我的计划的评论: 更新:我花了一下午的时间编写了一些代码,如下所示,有很多更好的方法

    ::SET VARS
        set "varDebugFP=\\svchafile\Teams\Test Engineering\Productivity Tools\MFG BAT Files\SpecificTest\"
        set varSource=%varDebugFP%Debug\
        set varDestination=%varDebugFP%Debug\
        set varFileName=specific.ini

    ::Do Text File Editing
        setlocal enableDelayedExpansion
        set "LastGroup=NONE"
        ::preserve blank lines using FINDSTR, even if a line may start with :
        for /f "usebackq delims=*" %%A in (`type "%srcFile%" ^| findstr /n "^"`) do         (
            set "strLine=%%A"
            set "strLine=!strLine:*:=!"

            ::Check to see if the is defined and greater than 2 characters inidicating a good line
            if defined strLine if NOT "!strLine:~2,1!"=="" if         "!strLine:~0,1!!strLine:~-1!"=="[]" (set "LastGroup=!strLine!")

            ::Set the paramaters looking to match
            set "DesiredGroup=[TestGroup]"
            set "DesiredItem=TestItem"
            set "ReplaceLineWith=NewTestItemLine=NewData"
            ::Look for match on current line
            if defined strLine if "!LastGroup!"=="!DesiredGroup!" if NOT "!strLine!"=="!strLine:TestItem=Mod!" (set "strLine=!ReplaceLineWith!")
            ::Note, in the above line I would like 'TestItem' to be the 'DesiredItem' variable but I can't get it working due to the DelayedExpansion

            ::Set the additonal paramaters looking to match
            ::Note, there are multiple items I want to change at once without having to reitterate through the org long (2000+lines) file
            set "DesiredGroup=[TestGroup2]"
            set "DesiredItem=TestItem2"
            set "ReplaceLineWith=NewTestItemLine2=NewData2"
            if defined strLine if "!LastGroup!"=="!DesiredGroup!" if NOT "!strLine!"=="!strLine:TestItem=Mod!" (set "strLine=!ReplaceLineWith!")

            ::I plan to copy and paste the above section as many times as needed to capture all the lines I need to edit (at this point about ~10)

            ::I don't really understand why the "(" in the below line, I found it in an example on stackoverflow and it seems to work.
            echo(!strLine!>>"%newFile%"
        )
        endlocal


    ::Replace org file with new file, delete org file (this part I have figured out)    
有更好的方法吗?有谁能帮我完成这段代码吗?因为我在正确解析这段代码时遇到了很多困难

更新:感谢以下答案中提出的两种方法。它们很长,我从它们身上学到了很多。但是,我不完全确定如何实现这些函数,我最大的担心是,使用该函数会使文件的重复读取大大降低速度。我对这个bat文件非常陌生,但我知道如果你知道命令并且富有创造性,它会非常强大


提前感谢您的帮助-Dan

那么多人想使用batch编辑文本文件-有很多关于这个主题的问题。但是,仅使用本机批处理命令很难(而且速度相对较慢)稳健地执行此操作

你最好使用其他工具。一个好的选择是使用sed或awk的免费Windows端口。但这需要将非本机可执行文件下载到您的计算机上,这在许多办公室是禁止的

我已经写信了。该脚本仅使用从XP开始的所有现代Windows计算机都可以使用的本机脚本。脚本中嵌入了完整的文档,包括指向描述所有可用JScript regex元字符的MicroSoft页面的链接

假设REPL.BAT在当前目录中,或者更好地说,在路径中的某个地方,那么可以使用以下简单的批处理脚本来修改特定子系统中任何项的值

::MODIFY_CONFIG.BAT  File  SubSystem  Item  NewValue
::
::  Any argument that contains spaces or special characters should be quoted.
::
::  File      = File to modify, may include full path
::  SubSystem = The section containing the item to modify (without brackets)
::  Item      = The Item within the SubSystem that is to be modified
::  NewValue  = The new value for the item

@echo off
type "%~1"|repl "(^ *\[%~2] *\r?\n(?: *[^[].*\n)*? *%~3=)[^\r\n]*" "$1%~4" m >"%~1.new"
move /y "%~1.new" "%~1" >nul
下面是对脚本的调用,该脚本将PressureLevel Control中的对齐方式更改为12345

MODIFY_CONFIG yourFile.ini PressureLevelControl Alignment 12345
@ECHO关闭
SETLOCAL
::读取参数
:%1是子组
:%2是项目
:%3是新值
:%3缺少=报告值
设置“子组=%~1”
设置“项=%~2”
设置“newval=%~3”
如果未定义子组回显语法:%~nx0“subgroup”“item”“newvalue”&GOTO:EOF
如果未定义项回显语法:%~nx0“子组”“项”“新值”&转到:EOF
回声%*
::状态=0(查找子组)1(找到子组)
设置/a状态=0
::结果=0(未执行任何操作)2(找到子组,而不是数据行)3(多次找到子组)
::4(找到并替换数据行)5(多次找到子组,替换数据一次)
::6(检测到数据线多次,替换一次)9(仅报告-找到值)
设置/a结果=0
(
对于/f“tokens=1*delims=:”%%a IN('findstr/n/r“^”q21263073.txt)DO(
设置“行=%%b”
呼叫:进程
如果定义了复制回波(%%b
快速眼动暂停
)
)>newfile.txt
设置“replacefile=”
呼叫:报告%result%
如果定义了replacefile ECHO,则会创建一个新文件
后藤:EOF
:report0
未找到回显[%subgroup%]
后藤:eof
:报告2
未找到回显[%subgroup%]%项%
后藤:eof
:报告3
重复找到回显[%subgroup%]-%item%未找到
后藤:eof
:报告4
发现ECHO[%subfound%]%olditem%已将%oldvalue%替换为%newval%
设置replacefile=Y
后藤:eof
:报告5
重复找到回显[%subgroup%]-%olditem%已找到,将%oldvalue%替换为%newval%
后藤:eof
:报告6
回显[%subgroup%]%重复找到项目%-%olditem%发现将%oldvalue%替换为%newval%一次
后藤:eof
:报告9
找到值为%oldvalue%的回显[%subgroup%]%olditem%
后藤:eof
:进程
::空行?
设置复制=Y
如果未定义行GOTO:EOF
如果“%line:~0,1%%line:~-1%”=“[]”转到fsubsys
::仅当状态为1时处理数据行
如果不是%state%==1转到:EOF
如果%result%gtr 5转到:EOF
设置“fvalue=”
对于/f“tokens=1*delims==”(“%line%”)中的%%p,请设置“fitem=%%p”并设置“fvalue=%%q”
::我们是否有一个item=价值行?
如果未定义fvalue GOTO:EOF
调用:匹配“%fitem%”%item%”
如果未定义匹配的转到:eof
::我们在子组中找到了一个匹配项。
::结果必须是2、3、4或5
对于(2.4 3.5 4.6 5.6)中的%%z,如果%result%=%c SET result=%d,则为/f“令牌=1,2 delims=。”%c IN(“%%z”)执行
如果%result%==6转到:EOF
::尚未替换值
我们有替代品吗?
设置“olditem=%fitem%”和设置“oldvalue=%fvalue%”
如果未定义,则newval SET result=9&GOTO:eof
设置“复制=”
回显(%fitem%=%newval%
后藤:eof
::找到子组名称
:fsubsys
设置/a状态=0
这就是我们要找的那个吗?
调用:匹配“%line:~1,-1%”%subgroup%
如果未定义匹配的转到:eof
设置/a状态=1
对于(0.2.3.4.5)中的%%z,如果%result%%==%c SET result=%d,则为/f“令牌=1,2 delims=。”%c IN(“%%z”)中的%%z
如果%result%==2,则设置“子基金=%line:~1,-1%”
后藤:eof
::将%1与%2匹配。如果匹配,则将匹配设置为非空。如果不匹配,则将匹配设置为空
当前位置这是我们可以玩的地方。
:匹配
设置“匹配=”
东南方
MODIFY_CONFIG yourFile.ini PressureLevelControl Alignment 12345