views:

172

answers:

2

Hi,

I'm trying to write a windows batch file that would read in a text file with certain text in it and increment some values in that file.

The text file would contain text like :

public static const COUNTER:int = 0

the batch file would then search for "COUNTER:int = 0" and increment the 0 value.

Unfortunately my knowledge of windows batch files is non-existent, so any advice or help on the matter is appreciated!

Thanks!

+3  A: 

I'd advise against using batch files for parsing files. It just doesn't play nicely with such things.

If you are absolutely sure that your file can never contain the following characters: &, |, >, <, " then you can use a batch file. But catering for those characters is hard and and—in some cases—downright impossible.

In such cases you would be better off either using VBScript to process the file or using various UNIX tools to perform that task. This might be possible using awk.

Note that Windows 7 includes Windows PowerShell where such a task is really trivial. And it can be installed separately on Windows XP and higher.

However, I think I'd go with a VBScript solution here.

If your requirements match above constraints, you can do it with a batch file. The one below should work.


First of all, we need delayed expansion, so this has to be one of the very first lines in the batch:

setlocal enableextensions enabledelayedexpansion

You can iterate over the lines in a file using for /f:

for /f "delims=" %%x in (my_file) do call :process "%%x"
goto :eof

:process
    ...
goto :eof

This will call the subroutine process for each line of the file, handing over the line as argument. The delims= part specifies that we don't want tokenizing on that line. We now look at the contents of that routine.

Fist we need to know whether the line even contains the string we're looking for (Note that the loop variable, containing the line is only %%x inside of the loop, in the subroutine it becomes %1):

echo %1 | findstr "COUNTER:int" >nul 2>&1
if not errorlevel 1 (
    ...
) else (
    echo %~1>>new_file
)

Inside, where now the ... are, we can handle that line in case it contains the search string. We first need to dissect it. The easiest way would be to split it up at the = character and then we increment the number and output everything again.

for /f "tokens=1,2 delims==" %%a in (%1) do (
    set /a number=%%b+1
    echo %%a= !number!>>new_file
)

So, putting it all together, it looks like this:

@echo off
setlocal enableextensions enabledelayedexpansion
del new_file

for /f "delims=" %%x in (my_file) do call :process "%%x"
goto :eof

:process
    echo %1 | findstr "COUNTER:int">nul 2>&1
    if not errorlevel 1 (
        for /f "tokens=1,2 delims==" %%a in (%1) do (
            set /a number=%%b+1
            echo %%a= !number!>>new_file
        )
    ) else (
        echo %~1>>new_file
    )
goto :eof

Code can be found in my SVN.

Joey
Hi,thank you for the explanation in detail, i'm learning alot, but i can't seem to get it to work. There are more lines that contain a string like "OTHERCOUNTER:int" and these get spliced out, and it appears it doesn't like it when there is something else in the template like :String or such. Can you help me with this template?
Trikke
This is the template : Only BUILD should be incremented. Meanwhile,i'll fumble around with this script.Thanks!package version{ public class Version { public static const MAJOR:int = 0 public static const MINOR:int = 0 public static const BUILD:int = 0 public static const REVISION:int = 0 public static function getString():String { return MAJOR + "." + MINOR; } }}
Trikke
The part where it checks for the lines it should increment is the one with `findstr`. You can easily adapt the pattern it looks for by changing that line. If it shouldn't match `OTHERCOUNTER` then you can just supply a space before `COUNTER`, such as: `" COUNTER:int"`.
Joey
A: 

If you've got sed, you can do this:

sed "s/COUNTER:int *= *0/COUNTER = 1/" file.cs >newfile.cs

This assumes that you're only looking for a particular constant name and wanting to change '0' to '1'.

Loadmaster
No, the number can change and needs to be incremented. Just replacing 0 by 1 won't help.
Joey
Like I said, it assumes a single case. You can still use `sed` if the number of cases is small (the OP didn't say).
Loadmaster