25

I have written a batch script to find and replace a string in a text file. Following is my script.

@echo off &setlocal
set "search=%1"
set "replace=%2"
set "textfile=Input.txt"
set "newfile=Output.txt"
(for /f "delims=" %%i in (%textfile%) do (
    set "line=%%i"
    setlocal enabledelayedexpansion
    set "line=!line:%search%=%replace%!"
    echo(!line!
    endlocal
))>"%newfile%"
del %textfile%
rename %newfile%  %textfile%

I am able to replace the word successfully.

But i dont want to create Output.txt and then rename it the original file..

Please help me out for editing a text file without redirecting the output to a new file..

Matthieu
  • 2,736
  • 4
  • 57
  • 87
ananth joshi
  • 747
  • 3
  • 9
  • 11
  • Cant we open the file in edit mode and modify it while reading? I dont have any idea on this..Let me know if its possible.. – ananth joshi Apr 15 '14 at 06:24
  • You can also use **[fart](https://sourceforge.net/projects/fart-it/)(Find And Replace Text)** command line utility to perform this task. – amanzoor Oct 25 '17 at 16:13

1 Answers1

50
@echo off

setlocal enableextensions disabledelayedexpansion

set "search=%1"
set "replace=%2"

set "textFile=Input.txt"

for /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
    set "line=%%i"
    setlocal enabledelayedexpansion
    >>"%textFile%" echo(!line:%search%=%replace%!
    endlocal
)

for /f will read all the data (generated by the type comamnd) before starting to process it. In the subprocess started to execute the type, we include a redirection overwritting the file (so it is emptied). Once the do clause starts to execute (the content of the file is in memory to be processed) the output is appended to the file.

sashoalm
  • 75,001
  • 122
  • 434
  • 781
MC ND
  • 69,615
  • 8
  • 84
  • 126
  • 3
    What does ^& break ^> means? – ananth joshi Apr 15 '14 at 07:14
  • 4
    @ananthjoshi, it erases the file contents. It is nothing more than `break > file`, just an command with no output redirected to the file. The file content gets erased. The carets before the `&` and `>` are to escape them inside the `for /f` command. – MC ND Apr 15 '14 at 07:45
  • One more query..I executed the script..It is taking close to 7 minutes to replace a word in a 12MB file..Can we make it faster by making use of find or findstr command? – ananth joshi Apr 15 '14 at 14:42
  • @ananthjoshi, find or findstr will only make it slower if used to test if the line contains or not the string. They will make it faster if the number of chnages were small and the order of lines were not important, as this could be done in two steps, one for the lines without replaces and other for the lines with replaces. But an aditional step should be necessary to resort the lines if required. Better take a look at `repl.bat`, a batch tool from dbenham. See [here](http://www.dostips.com/forum/viewtopic.php?f=3&t=3855) for more information – MC ND Apr 15 '14 at 19:00
  • @MCND - Your script solve my problem but since I have a multi line assigned for the **replace** variable, do you know how to save a multi line into it? And then every time you run the script the output will also display into multi line not one line. – lovelyvm Jan 26 '16 at 03:57
  • 2
    This _almost_ worked for me, but it strips out `!` from the file I'm replacing the text of. I haven't found a way around it yet. – Dov Jun 15 '16 at 14:17
  • 5
    @Dov, remove the `set "line=!line:%search%=%replace%!"` and change the next line into `>>"%textFile%" echo(!line:%search%=%replace%!`. – MC ND Jun 16 '16 at 08:30
  • Is there any way that I can include regEx search for finding a string out ? – P-RAD Dec 11 '16 at 17:52
  • @wmc, yes, the `for /f` skips them. Usually the problem is handled by replacing the `type` with `findstr /n "^"` to get numbered lines (and not have empty lines), but additional code is needed to remove the initial numbers and colon. – MC ND Mar 22 '17 at 10:25
  • 1
    what does the parenthesis `(` after `echo` do? – Rayhunter Aug 06 '17 at 20:07
  • 2
    @Rayhunter, it avoids a `echo is off` output if, after doing the replace, there is not any data to output. – MC ND Aug 06 '17 at 20:23
  • 1
    Hi. how can i do it multiple times with different strings? copy and pasting this multiple times doenst work ` >>"%textFile%" echo(!line:%search%=%replace%!` its not overwriting the search word – Lorence Hernandez Feb 22 '18 at 01:26
  • 1
    @LorenceHernandez, you need to execute multiple times something like `set "line=!line:replacethis=withthis!"` (using literals or variables) and once all the changes are made in `line` then write the output `>>"%textFile%" echo(!line!`. Note that this approach (native variable substring replacement) have some problems with some characters (`!=~`) – MC ND Feb 22 '18 at 09:08
  • @MCND I've been playing around with this the last couple of days and ran into interesting snags with expansion and my source values I'm looking for (which are wrapped in ##). I've been able to do work arounds for those by hardcoding the search values and unrolling my calls instead of passing a variable. However, one thing I can't get around is that blank lines are being stripped from the file. Is there any way to keep blank lines? – Brian Knoblauch Sep 25 '20 at 00:11
  • 1
    @BrianKnoblauch, `for` command don't execute the `do` clause for empty lines as they don't provide data to populate tokens. The usual way to deal with it is to use `findstr /n "^"` (instead of `type` in code sample) to numerate lines and then, inside the `do` clause, discard the numbers. – MC ND Sep 26 '20 at 09:09
  • @MCND Ah, got it, thank you. "discard the numbers" turned into a bit of an adventure to figure out how to do it, but I did get a workable (if not elegant) solution. I keep finding that there's so many things that seem simple in other languages that when attempted in a batch file explode in strange and amazing ways. Delayed expansion is a common culprit I'm finding, but isn't always the reason. :-) – Brian Knoblauch Sep 27 '20 at 19:02
  • How would you amend the script if you were just carrying out the find replace on the first row, rather than going through the entire txt file?? – KMoe Sep 15 '21 at 01:24
  • @KMoe, maybe I would wrap the `for` inner code inside `if not defined line (......) else (......) ` just ensure line is not defined before starting the loop, but, with this method, you will need to read and write the whole file – MC ND Sep 15 '21 at 19:00
  • Thank you! I don't use batch files often, so that was very helpful. I did have to add an 'Exit /b" at the end of the script to get it to return control gracefully. Am I overlooking something, or is that reasonable? – Robert Cody Mar 28 '23 at 18:25
  • Is it possible to use a wildcard character like `*` within the definition of the `search` variable? Given there are occurences of the sequence `.000`, `.001`, `.002` and I want to replace each one like `.00*` with `.tif`. Because some ancient software enumerates its output tif images by the extension. _Shiver_. – procra Jun 15 '23 at 12:12
  • 1
    @RobertCody if you call this script from another .bat file or a .cmd file you usually have to add `exit /b` at the end of file if you intend to return control to the calling script because you're probably doing something more there afterwards. – procra Jun 15 '23 at 12:15