This simpler Batch file do what you want. The trick used to replace just the first appearance of the search string consists in use the !line:*%search%=!"
replacement, that replaces from the beginning of the line up to the first appearance of the search string, twice: first to get the "tail" of the line, and then to get the "head" of the line by removing the tail.
@echo off
setlocal EnableDelayedExpansion
set "base=fox"
set "search=brown"
set "change=white"
rem Assemble a list of line numbers that contains *both* terms
set "list="
for /F "delims=:" %%a in ('findstr /N "%base%" test.txt ^| findstr "%search%"') do (
set "list=!list! %%a"
)
if not defined list echo Search lines not found & goto :EOF
rem Get the first line number
for /F "tokens=1*" %%x in ("%list%") do set "lineNo=%%x" & set "list=%%y 0"
rem Process the file
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" test.txt') do (
set "line=%%b"
if %%a equ !lineNo! (
rem Line with both search strings found:
rem Replace the term in line, just the first time
set "tail=!line:*%search%=!"
for %%x in ("!line:*%search%=%search%!") do set "line=!line:%%~x=%change%!!tail!"
rem Get next line number from list
for /F "tokens=1*" %%x in ("%list%") do set "lineNo=%%x" & set "list=%%y
)
echo(!line!
)
I changed the line 4 of your input data file to this one in order to get a line with two "brown" strings:
The quick brown fox jumped over the lazy brown dog
This is the output:
The quick white fox jumped over the lazy white dog
The quick red fox jumped over the lazy dog
The quick green wolf jumped over the lazy brown dog
The quick white fox jumped over the lazy brown dog
The quick red lion jumped over the lazy dog
The quick green pig jumped over the lazy brown dog
The quick brown fox jumped over the lazy dog
You could also solve this problem in a very different way using my printf.exe version 2.11 program.
My printf.exe application is a Windows console program that is a wrapper for the well-known printf CRT function, thus allowing text and formatted numeric values to be displayed in the cmd.exe window. In addition, my program printf.exe also allows to perform Reverse Polish Notation arithmetic operations on 32-bit integers and 64-bit double floating-point numbers using the same method and functions of the stack-based Hewlett-Packard calculators.
The new printf.exe version 2.11 also manages character string operations and allows to write scripts (programs) using the simplest programming scheme. The Batch file below contains a printf.exe program that also solves this problem. Note that the printf.exe's method (clearly explained in the extensive comments) is even simpler than the previous Batch file's one.
@echo off
setlocal
rem Replace a string if another string is present in the line using Aacini's printf.exe
rem Antonio Perez Ayala
set "base=fox"
set "search=brown"
set "change=white"
< test.txt printf "%%s\n" /* line format */ ^
( /* WHILE NOT EOF */ ^
/" <* /" /* Clear the stack */ ^
80 /* 80 (max line length) */ ^
( IN? )? /* "The quick brown fox jumped over the lazy brown dog" len */ ^
; /* EOF? QUIT */ ^
/" < /" /* "The quick brown fox jumped over the lazy brown dog" Drop len */ ^
]0 /* "The quick brown fox jumped over the lazy brown dog" Store line address in R0 */ ^
base /* "The quick brown fox jumped over the lazy brown dog" "fox" Load base search string */ ^
index /* "The quick brown fox jumped over the lazy brown dog" 16 1 Indices of "fox" */ ^
==0? /* IF line have not "fox": */ ^
OUT /* Show it */ ^
: /* and CONTINUE the loop */ ^
/" <* /" /* Clear stack */ ^
[0 /* Recall string address */ ^
1 dups /* "The quick brown fox jumped over the lazy brown dog" Recall string */ ^
search /* "The quick brown fox jumped over the lazy brown dog" "brown" Load search string */ ^
index /* "The quick brown fox jumped over the lazy brown dog" 10 41 2 Indices of "brown" */ ^
==0? /* IF line have not "brown": */ ^
OUT /* Show it */ ^
: /* and CONTINUE the loop */ ^
shift /* "The quick brown fox jumped..." 41 1 10 Get first index */ ^
[0 /* "The quick brown fox jumped..." 41 1 10 R0 String address */ ^
+ /* "The quick brown fox jumped..." 41 1 R0+10 Address of "brown" */ ^
0 movc1 /* "The quick 0rown fox jumped..." 41 1 R0+10 Cut the string there */ ^
search /* "The quick 0rown fox jumped..." 41 1 R0+10 "brown" Load search string */ ^
len /* "The quick 0rown fox jumped..." 41 1 R0+10 "brown" 5 Len of "brown" */ ^
/" <2 /" /* "The quick 0rown fox jumped..." 41 1 R0+10 5 Drop "brown" */ ^
+ /* "The quick 0rown|fox jumped..." 41 1 R0+10+5 Address of end of "brown" */ ^
]1 /* "The quick 0rown|fox jumped..." 41 1 R0+10+5 Store it in R1 */ ^
FMT{ "%%s" [0 OUT /* Show first part: "The quick " */ ^
/" < /" change OUT /* Show replacement: "white" */ ^
FMT} /* Format end */ ^
/" <* /" [1 OUT /* Show second part: " fox jumped..." */ ^
: /* REPEAT */ ^
) /* ENDWHILE */
Although it may seem complicated, the printf.exe instructions are very simple. HP calculator users can start writing printf.exe programs in minutes after understanding the differences and the programming scheme. You can review another example of a printf.exe program at this answer
You can download the printf.exe package from this link