Windows 用批处理替换多个文件的字符串

Windows 用批处理替换多个文件的字符串,windows,batch-file,cmd,Windows,Batch File,Cmd,我正在尝试使用建议的脚本 我的目标是能够为多个文件重用脚本。 我有一个文件包含这个脚本,另一个文件只是用不同的参数多次触发脚本 ReplaceString.bat @echo off REM -- Prepare the Command Processor -- SETLOCAL ENABLEEXTENSIONS SETLOCAL DISABLEDELAYEDEXPANSION ::BatchSubstitude - parses a File line by line and replace

我正在尝试使用建议的脚本

我的目标是能够为多个文件重用脚本。 我有一个文件包含这个脚本,另一个文件只是用不同的参数多次触发脚本

ReplaceString.bat

@echo off
REM -- Prepare the Command Processor --
SETLOCAL ENABLEEXTENSIONS
SETLOCAL DISABLEDELAYEDEXPANSION

::BatchSubstitude - parses a File line by line and replaces a substring"
::syntax: BatchSubstitude.bat OldStr NewStr File
::          OldStr [in] - string to be replaced
::          NewStr [in] - string to replace with
::          File   [in] - file to be parsed
:$changed 20100115
:$source http://www.dostips.com
if "%~1"=="" findstr "^::" "%~f0"&GOTO:EOF
for /f "tokens=1,* delims=]" %%A in ('"type %3|find /n /v """') do (
    set "line=%%B"
    if defined line (
        call set "line=echo.%%line:%~1=%~2%%"
        for /f "delims=" %%X in ('"echo."%%line%%""') do %%~X
    ) ELSE echo.
)
set oldString=foo
set newString=newFoo

ReplaceString.bat %oldString% %newString% someFile.txt >someFile.txt

ReplaceString.bat %oldString% %newString% someFile2.txt >someFile2.txt
让我们说:

foo.bat

@echo off
REM -- Prepare the Command Processor --
SETLOCAL ENABLEEXTENSIONS
SETLOCAL DISABLEDELAYEDEXPANSION

::BatchSubstitude - parses a File line by line and replaces a substring"
::syntax: BatchSubstitude.bat OldStr NewStr File
::          OldStr [in] - string to be replaced
::          NewStr [in] - string to replace with
::          File   [in] - file to be parsed
:$changed 20100115
:$source http://www.dostips.com
if "%~1"=="" findstr "^::" "%~f0"&GOTO:EOF
for /f "tokens=1,* delims=]" %%A in ('"type %3|find /n /v """') do (
    set "line=%%B"
    if defined line (
        call set "line=echo.%%line:%~1=%~2%%"
        for /f "delims=" %%X in ('"echo."%%line%%""') do %%~X
    ) ELSE echo.
)
set oldString=foo
set newString=newFoo

ReplaceString.bat %oldString% %newString% someFile.txt >someFile.txt

ReplaceString.bat %oldString% %newString% someFile2.txt >someFile2.txt
但无论出于何种原因,在成功运行第一个调用后,执行将停止

我试图用
START
&
call
调用
ReplaceString.bat
,试图不将输出重定向到文件,但每次都得到相同的结果

我希望能够强制
foo.bat
继续运行,或者
ReplaceString.bat
不退出

编辑: 我错误地认为脚本提前结束了,但实际发生的是,我没有接收到控制台的输出,命令是使用
CALL
command运行的。
我的脚本的另一个问题是将输出重定向回输入文件,这是通过将输出重定向到临时文件并在调用结束后将其替换为原始文件来解决的

ReplaceString.bat
起作用,但您在
foo.bat
中以有问题的方式使用它;您应按以下方式进行更改:

set oldString=foo
set newString=newFoo

CALL ReplaceString.bat %oldString% %newString% someFile.txt  >someFileX.txt

CALL ReplaceString.bat %oldString% %newString% someFile2.txt >someFile2X.txt
  • 请注意,调用从一个批处理程序调用另一个批处理程序:
  • 调用第二个批处理文件
    调用
    命令将启动新的批处理文件上下文以及任何指定参数。什么时候结束 到达第二个批处理文件的第二个批处理文件(或者如果使用了
    EXIT
    ),则控制 将在初始
    CALL
    语句之后返回到

    参数可以作为简单字符串或使用变量传递

  • 请注意,如果将
    ReplaceString.bat
    输出重定向到与在
    ReplaceString.bat%oldString%%newString%someFile.txt>someFile.txt
    中解析的文件相同的文件,则将首先清空输出文件,以便调用的脚本无需解析(或解析空文件)…使用不同的输入和输出文件,如上面的代码示例所示

  • 无论您在
    foo.bat
    中以有问题的方式使用
    ReplaceString.bat,该
    ReplaceString.bat
    都是有效的;您应按以下方式进行更改:

    set oldString=foo
    set newString=newFoo
    
    CALL ReplaceString.bat %oldString% %newString% someFile.txt  >someFileX.txt
    
    CALL ReplaceString.bat %oldString% %newString% someFile2.txt >someFile2X.txt
    
  • 请注意,调用从一个批处理程序调用另一个批处理程序:
  • 调用第二个批处理文件
    调用
    命令将启动新的批处理文件上下文以及任何指定参数。什么时候结束 到达第二个批处理文件的第二个批处理文件(或者如果使用了
    EXIT
    ),则控制 将返回到初始
    CALL
    语句之后

    参数可以作为简单字符串或使用变量传递

  • 请注意,如果将
    ReplaceString.bat
    输出重定向到与在
    ReplaceString.bat%oldString%%newString%someFile.txt>someFile.txt
    中解析的文件相同的文件,则将首先清空输出文件,以便调用的脚本无需解析(或解析空文件)…使用不同的输入和输出文件,如上面的代码示例所示

  • 首先,我建议将ReplaceString.bat更改为:

    @echo off
    rem -- Prepare the Command Processor --
    setlocal EnableExtensions DisableDelayedExpansion
    
    ::BatchSubstitude - parses a File line by line and replaces a substring"
    ::syntax: BatchSubstitude.bat OldStr NewStr File
    ::          OldStr [in] - string to be replaced
    ::          NewStr [in] - string to replace with
    ::          File   [in] - file to be parsed
    :$changed 20100115
    :$source http://www.dostips.com
    if "%~1"=="" %SystemRoot%\System32\findstr.exe "^::" "%~f0" & goto :EOF
    for /f "tokens=1,* delims=]" %%A in ('"type %3|%SystemRoot%\System32\find.exe /n /v """') do (
        set "line=%%B"
        if defined line (
            call set "line=echo.%%line:%~1=%~2%%"
            for /f "delims=" %%X in ('"echo."%%line%%""') do %%~X
        ) else echo.
    )
    endlocal
    
    每次使用setlocal都会创建整个环境表的副本,将指针推送到堆栈上的上一个环境表,推送到堆栈上命令扩展的当前状态和延迟扩展的当前状态,并推送到堆栈上的当前目录路径。只需一个setlocal就可以启用命令扩展(默认启用)和禁用延迟扩展(默认禁用)

    Windows command processor在到达批处理文件处理的退出点时将环境恢复为启动批处理文件时的状态。但是,对每个setlocal命令使用相应的endlocal是一个好主意

    使用完整路径和文件扩展名调用findstrfind也很好,因为在环境变量path中,在
    %SystemRoot%\System32
    之前包含一个文件夹路径,其中还包含从Unix移植的
    find.exe
    findstr.exe
    到Windows,但当然工作方式不同,或者是一个
    find.bat
    ,或者一个
    findstr
    ,其文件扩展名在环境变量PATHEXT中定义

    但在处理foo.bat时从未调用带
    ReplaceString.bat
    的第二行的主要原因是:

    带有
    ReplaceString.bat
    的第一行没有命令call

    因此,foo.bat的处理继续进行ReplaceString.bat,不再返回foo.bat作为非调用另一批处理文件

    foo.bat需要以下行:

    set oldString=foo
    set newString=newFoo
    
    call ReplaceString.bat %oldString% %newString% someFile.txt >someFile_1.txt
    move /Y someFile_1.txt someFile.txt
    
    call ReplaceString.bat %oldString% %newString% someFile2.txt >someFile_2.txt
    move /Y someFile_2.txt someFile2.txt
    
    有关更多详细信息,请参阅上的我的回答

    并且不可能将输出重定向到输入文件。必须将输出重定向到一个单独的文件,然后将该文件移到输入文件上

    还有一个注意事项:

    ReplaceString.bat适用于许多文件,但并非适用于所有文件内容

    例如,在上面运行略为改进的ReplaceString.bat版本

    ReplaceString.bat dostips mytips ReplaceString.bat >ReplaceString.txt
    
    导致出现意外的错误消息

    系统找不到指定的路径

    文件
    ReplaceString.txt
    在第11行按预期将
    dostips
    替换为
    mytips
    ,但第12行缺少
    ^
    ,批处理文件的第13行在ou中完全缺少