Reputation: 3399
I'm trying to use the script that was suggested here.
My goal is to be able to reuse the script for multiple files. I have one file that contains this script and another one that simply triggers the script multiple times with different parameters.
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.
)
And let's say:
foo.bat
set oldString=foo
set newString=newFoo
ReplaceString.bat %oldString% %newString% someFile.txt >someFile.txt
ReplaceString.bat %oldString% %newString% someFile2.txt >someFile2.txt
But for whatever reason, the execution stops after successfully running the first call.
I tried to call the ReplaceString.bat
with START
& CALL
, tried not to redirect the output to a file, but each time I ended up having the same result.
I would like to be able either forcing foo.bat
to continue to run, or ReplaceString.bat
not to exit.
Edit:
I mistakenly assumed the script was ending prematurely, but what was actually happening is, I just wasn't receiving an output to my console, the commands did run with CALL
command.
The other problem with my script was redirecting the output back to the input file, which was fixed by redirecting output to a temporary file and replacing it with the original once the call ended.
Upvotes: 1
Views: 1777
Reputation: 49085
First, I suggest to change ReplaceString.bat to:
@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
Each usage of setlocal results in creating a copy of entire environment table with pushing a pointer to previous environment table on stack, pushing current state of command extensions and current state of delayed expansion on stack and pushing also current directory path on stack. It is possible to enable command extensions (by default enabled) and disable delayed expansion (by default disabled) with just one setlocal.
Windows command processor restores the environment as it was on starting a batch file on reaching exit point on a batch file processing. But it is nevertheless a good idea to use for every setlocal the corresponding endlocal command.
It is also good to call findstr and find with full path and file extension as it can easily happen that in environment variable PATH there is a folder path included before %SystemRoot%\System32
which contains also a find.exe
or findstr.exe
ported from Unix to Windows, but of course working different, or a find.bat
, or a findstr
with a file extension defined in environment variable PATHEXT.
But the main reason why second line with ReplaceString.bat
is never called on processing foo.bat is:
The first line with ReplaceString.bat
is without command call.
Therefore processing of foo.bat continues with ReplaceString.bat with never coming back to foo.bat as not calling the other batch file.
The following lines are needed for 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
For more details see my answer on How to call a batch file in the parent folder of current batch file?
And it is not possible to redirect the output to input file. The output must be redirected to a separate file which is next moved over the input file.
One more note:
ReplaceString.bat works for many, but not for all file contents.
For example running above just slightly improved version of ReplaceString.bat with
ReplaceString.bat dostips mytips ReplaceString.bat >ReplaceString.txt
results in the unexpected error message
The system cannot find the path specified.
and the file ReplaceString.txt
has dostips
replaced by mytips
in line 11 as expected, but ^
is missing on line 12, and line 13 from batch file is missing completely in the output text file.
For alternatives see How can you find and replace text in a file using the Windows command-line environment?
Upvotes: 3
Reputation: 30103
That ReplaceString.bat
works however you use it in problematic way in foo.bat
; you should change it as follows:
set oldString=foo
set newString=newFoo
CALL ReplaceString.bat %oldString% %newString% someFile.txt >someFileX.txt
CALL ReplaceString.bat %oldString% %newString% someFile2.txt >someFile2X.txt
CALL a second batch file
TheCALL
command will launch a new batch file context along with any specified parameters. When the end of the second batch file is reached (or ifEXIT
is used), control will return to just after the initialCALL
statement.Arguments can be passed either as a simple string or using a variable.
ReplaceString.bat
output to the same file which is to be parsed as in ReplaceString.bat %oldString% %newString% someFile.txt >someFile.txt
, then the redirection operator >
will empty the output file first so that called script has nothing to parse (or parses an empty file)… Use different input and output files as shown in code sample above.Upvotes: 4