0

I need batch file that searches for a text (eg., FOO) and replaces it with another text (eg., BAR) in all the text files within a folder and it's sub-folders.

I need to give this batch file to the user. So, it is not possible to ask the user to install anything else and also i don't wanna add other files to my batch script, is that even passable? I found many answer for this issue but everyone advise to install other program or to add a file to the batch script . Can someone please help me with this?

aschipfl
  • 33,626
  • 12
  • 54
  • 99
David
  • 169
  • 4
  • 16
  • [This answer](https://stackoverflow.com/q/60034) and [this one](https://stackoverflow.com/q/42052039) show how to replace text, also using native Windows functions; try to implement your favourite solution inside of a loop to handle all matching files in a directory tree... – aschipfl Sep 28 '17 at 11:20

3 Answers3

4

Here is a simple and pure solution -- let us call it 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

To use this script, provide the search string as the first and the replace string as the second command line argument, respectively; the third argument defines the root directory which defaults to the current working directory, and the fourth one defines the file pattern which defaults to *.txt:

replac.bat "Foo" "Bar"

The following restrictions apply:

  • all matching files must be plain ASCII/ANSI text files with Windows-style line-breaks;
  • neither the lines in the files nor the search and replace strings may be longer than approximately 8190 bytes/characters;
  • the search string must not be empty, it must not begin with * or ~, and it must not contain =;
  • the search and replace strings must not contain ! or ^;
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • when I ran this it made the substitutions, but also echoed most of the contents of replac.bat to my test file – craq Jun 15 '20 at 05:26
  • 1
    Did you forget `@echo off` at the beginning of the script? – aschipfl Jun 15 '20 at 06:04
  • That's probably a good guess. I deleted the file so I can't check whether I missed that first line in my copy paste. I also can't change my vote because of that stupid rule with the 5 minute time limit, unless you edit the answer – craq Jun 15 '20 at 06:07
  • 1
    @craq, luckily there was an edit now, even to suspend one of the restrictions… – aschipfl Jun 15 '20 at 08:15
0
for /r %i in (bar.txt) do echo ren "%i" foobar.txt

Remove the echo ONLY once you are sure the files are going to be correctly renamed.

to use it in a Batch file, add additional % to the variables, like:

@echo off
for /r %%i in (bar.txt) do echo ren "%%i" foobar.txt
Gerhard
  • 22,678
  • 7
  • 27
  • 43
  • I want to change the text itself (inside the .txt file ) and not the name of the file :/ – David Sep 28 '17 at 11:24
  • 1
    @David ok, that was not very clear at all from your question. in that case, follow the link [here](https://stackoverflow.com/questions/60034/how-can-you-find-and-replace-text-in-a-file-using-the-windows-command-line-envir/16735079#16735079) – Gerhard Sep 28 '17 at 11:26
0

Oops, sorry, I just saw that you want a solution without installing anything... This doesn't apply to OP then, but might be useful to someone else so I'll leave it up.

If you install git bash (or mingw or cygwin etc) you can use sed, as explained in this answer: https://stackoverflow.com/a/11660023. Use globbing to match multiple files. e.g.

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

sed uses regexp, so you have access to powerful features like matching only the start of lines (^) or the end of lines ($), any number ([0-9]) etc.

craq
  • 1,441
  • 2
  • 20
  • 39