【问题标题】:Batch Script - Find and replace text in multiple files in a directory without asking user to install any program or add other files to my batch script批处理脚本 - 在目录中的多个文件中查找和替换文本,而不要求用户安装任何程序或将其他文件添加到我的批处理脚本
【发布时间】:2017-09-28 10:57:55
【问题描述】:

我需要一个批处理文件来搜索一个文本(例如 FOO)并将其替换为文件夹及其子文件夹中所有文本文件中的另一个文本(例如 BAR)。

我需要将此批处理文件提供给用户。因此,不可能要求用户安装其他任何东西,而且我不想将其他文件添加到我的批处理脚本中,这是否可以通过?我为这个问题找到了很多答案,但每个人都建议安装其他程序或将文件添加到批处理脚本。有人可以帮我解决这个问题吗?

【问题讨论】:

  • This answerthis one 展示了如何替换文本,也使用本机 Windows 功能;尝试在循环中实现您最喜欢的解决方案,以处理目录树中的所有匹配文件...

标签: windows batch-file replace cmd find


【解决方案1】:

这是一个简单而纯粹的 解决方案——让我们称之为replac.bat

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=%~3"   & rem // (path to root directory; third command line argument)
set "_MASK=%~4"   & rem // (file search pattern; fourth command line argument)
set "_SEARCH=%~1" & rem // (search string; first command line argument)
set "_REPLAC=%~2" & rem // (replace string; second command line argument)
set "_CASE=#"     & rem // (clear for case-insensitive search)
set "_RECURS=#"   & rem // (clear for non-recursive search)
set "_TMPF=%TEMP%\%~n0_%RANDOM%.tmp" & rem // (path to temporary file)

rem // Validate passed command line arguments, apply defaults:
if not defined _SEARCH exit /B 1
if not defined _ROOT set "_ROOT=."
if not defined _MASK set "_MASK=*.txt"

rem // Prepare `if` option (case-insensitivity) for later use:
if defined _CASE (set "IFSW=") else (set "IFSW=/I")
rem // Prepare `for` option (recursion) for later use:
if defined _RECURS (set "FOROPT=/R") else (set "FOROPT=")
rem // Change into root directory temporarily:
pushd "%_ROOT%" || exit /B 1
rem // Loop through all matching files in the directory tree:
for %FOROPT% %%F in ("%_MASK%") do (
    rem // Write to temporary file:
    > "%_TMPF%" (
        set "FLAG="
        rem /* Read current file line by line; use `findstr` to precede every line by
        rem    its line number and a colon `:`; this way empty lines appear non-empty
        rem    to `for /F`, which avoids them to be ignored; otherwise empty lines
        rem    became lost: */
        for /F "delims=" %%L in ('findstr /N "^" "%%~fF"') do (
            rem // Store current line text:
            set "LINE=%%L"
            setlocal EnableDelayedExpansion
            rem // Remove line number prefix:
            set "LINE=!LINE:*:=!"
            rem // Skip replacement for empty line text:
            if defined LINE (
                rem /* Use `for /F` loop to avoid trouble in case search or replace
                rem    strings contain quotation marks `"`: */
                for /F "tokens=* delims=*= eol=~" %%K in ("!_SEARCH!=!_REPLAC!") do (
                    rem // Split search and replace strings:
                    for /F "tokens=1 delims== eol==" %%I in ("%%K") do (
                        rem // Query to handle case-sensitivity:
                        if %IFSW% "!LINE!"=="!LINE:%%I=%%I!" (
                            rem // Detect whether replacement changes line:
                            if not "!LINE!"=="!LINE:%%K!" (
                                rem // Actually do the sub-string replacement:
                                set "LINE=!LINE:%%K!"
                                set "FLAG=#"
                            )
                        )
                    )
                )
            )
            rem // Output the resulting line text:
            echo(!LINE!
            if defined FLAG (endlocal & set "FLAG=#") else (endlocal)
        )
    )
    rem // Check whether file content would change upon replacement:
    if defined FLAG (
        rem // Move the temporary file onto the original one:
        > nul move /Y "%_TMPF%" "%%~fF"
    ) else (
        rem // Simply delete temporary file:
        del "%_TMPF%"
    )
)
popd

endlocal
exit /B

要使用此脚本,请分别提供搜索字符串作为第一个命令行参数和替换字符串作为第二个命令行参数;第三个参数定义默认为当前工作目录的根目录,第四个参数定义默认为*.txt的文件模式:

replac.bat "Foo" "Bar"

适用以下限制:

  • 所有匹配文件必须是纯 ASCII/ANSI 文本文件,带有 Windows 样式的换行符;
  • 文件中的行和搜索和替换字符串都不能超过大约 8190 个字节/字符;
  • 搜索字符串不能为空,不能以*~开头,不能包含=
  • 搜索和替换字符串不能包含!^

【讨论】:

  • 当我运行它时,它进行了替换,但也将 repac.bat 的大部分内容回显到我的测试文件中
  • 您是否忘记了脚本开头的@echo off
  • 这可能是个不错的猜测。我删除了该文件,因此无法检查是否错过了复制粘贴中的第一行。由于 5 分钟时间限制的愚蠢规则,我也无法更改我的投票,除非您编辑答案
  • @craq,幸运的是现在有一个编辑,甚至暂停其中一个限制......
【解决方案2】:
for /r %i in (bar.txt) do echo ren "%i" foobar.txt

只有在您确定文件将被正确重命名后,才能删除 echo

要在批处理文件中使用它,请在变量中添加额外的%,例如:

@echo off
for /r %%i in (bar.txt) do echo ren "%%i" foobar.txt

【讨论】:

  • 我想更改文本本身(在 .txt 文件中)而不是文件名:/
  • @David 好的,从你的问题来看,这一点都不是很清楚。在这种情况下,请点击链接here
【解决方案3】:

糟糕,抱歉,我刚刚看到您想要一个不安装任何东西的解决方案...这不适用于 OP,但可能对其他人有用,所以我会保留它。

如果您安装 git bash(或 mingw 或 cygwin 等),您可以使用 sed,如此答案中所述:https://stackoverflow.com/a/11660023。使用通配符匹配多个文件。例如

sed -i 's/FOO/BAR/g' ./*.txt

sed 使用正则表达式,因此您可以使用强大的功能,例如仅匹配行首 (^) 或行尾 ($)、任意数字 ([0-9]) 等。

【讨论】:

    猜你喜欢
    • 2015-02-03
    • 2013-04-11
    • 2020-04-27
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多