I personally do not like always creating applications for basic tasks. This is even the case when writing an application is probably easier than doing the same with batches, but I like these challenges. In my case, I had a few videos I wanted to process with AviSynth. Rather than creating multiple copies of the AviSynth script, I wanted to create a template where all other derive from.
Reading a file line by line
The file will be processed line by line. We can achieve this with a simple for-loop. The following example will simply cycle through all lines of the file input.txt and print them to the console. The %%a variable will hold the text of the currently processed line.
1 |
for /f "usebackq delims=" %%a in ("input.txt") do (echo %%a) |
A little drawback is that this method will strip empty lines and lines starting with a semicolon. The parameter usebackq is required in order to use quotes within the filename set (here “input.txt”).
You can avoid stripping of lines beginning with a semicolon by passing an alternative eol symbol. In the following example, I’ll use a colon as an alternative.
1 |
for /f "usebackq eol=: delims=" %%a in ("input.txt") do (echo %%a) |
Replacing placeholders
As we’re now able to read a file line by line, next thing on the list to start replacing our placeholders. To avoid invalid matches, I used the special combination @@ at the beginning and the end of the variable (no special reason behind this).
1 2 3 4 5 6 |
set CURRENT_LINE=Hello, this is some @@REPLACE_ME@@, yup echo Before: %CURRENT_LINE% set CURRENT_LINE=%%CURRENT_LINE:@@REPLACE_ME@@=new value%% echo After: %CURRENT_LINE% |
Replacement with variables is no special task either. But due to the nesting of variables, we have to make use of call.
1 2 3 4 5 6 7 8 |
set CURRENT_LINE=Hello, this is some @@REPLACE_ME@@, yup echo Before: %CURRENT_LINE% set VARIABLE_NAME=@@REPLACE_ME@@ set NEW_VALUE=test value call set CURRENT_LINE=%%CURRENT_LINE:%VARIABLE_NAME%=%NEW_VALUE%%% echo After: %CURRENT_LINE% |
The reason for the use of the call command is required in order to nest variables. With the execution of call, the first set of variables will be interpreted. In this case, this would be VARIABLE_NAME and NEW_VALUE. After this, the actual set command is being executed where the string replacement is being run on the CURRENT_LINE variable.
The use of the double %-symbol is used to escape the %. So therefore, during the execution of call, the %% will change to %. The execution will somehow look like this.
1 2 3 4 5 |
set CURRENT_LINE=Hello @@VARIABLE2@@ set HELLO_WORLD=world call set CURRENT_LINE=%%CURRENT_LINE:@@VARIABLE2@@=%HELLO_WORLD%%% set CURRENT_LINE=%CURRENT_LINE:@@VARIABLE2@@=world% |
Processing the template file
Finally we have to combine the file reading, the string replacement and writing the output file. We use the the >> operator instead of the > one. The difference between these two is, the former appends lines to a file whereas the latter owerwrites the file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
set INPUT_FILE="input.txt" set OUTPUT_FILE="output.txt" set HELLO_WORLD=world del %OUTPUT_FILE% for /f "usebackq delims=" %%a in (%INPUT_FILE%) do (call :PROCESS_LINE %%a) GOTO :EOF :PROCESS_LINE set CURRENT_LINE=%* set CURRENT_LINE=%CURRENT_LINE:@@VARIABLE1@@=new value% call set CURRENT_LINE=%%CURRENT_LINE:@@VARIABLE2@@=%HELLO_WORLD%%% echo %CURRENT_LINE% >> "%OUTPUT_FILE% :EOF |
I split the replacement from the for loop because it would require delayed expansion. It would also be possible (and probably cleaner) to create a separate batch file for this.