Batch scripting - parsing file line by line and finding string - batch-file

I'm trying to parse a .txt file using batch script, line by line, untill I find "arg =" string and then get the following number. To put it into context, I'm trying to parse this gdb.txt file
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x00007c2c in ?? ()
Loading section .sec1, size 0x20000 lma 0x0
Start address 0x8560, load size 131072
Transfer rate: 103 KB/sec, 1110 bytes/write.
Command Executed successfully: semihosting enable
Breakpoint 1 at 0x790a: file C:\LMA\ws_new\wam_sdk1886.31.001.1C_ver1\src\sdk\wam\bsp\detail/exit.c, line 21.
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 1, exit (arg=0) at C:\LMA\ws_new\wam_sdk1886.31.001.1C_ver1\src\sdk\wam\bsp\detail/exit.c:21
21 volatile std::uint8_t a = 0;
arg = 0
[Inferior 1 (Remote target) detached]
I've come up with these few lines of batch script:
#echo off
for /f delims^=^ eol^= %%A in (gdb.txt) Do (
echo %%A
findstr /c:"arg =" %%A>nul 2>nul
echo %errorlevel%
)
I would like the script to recognize the line with "arg =" so I can read 0 afterwards.
However this script seems not to be able to recognize "arg =" and always prints %errorlevel% as 1.
What am I missing here?

It's much easier to filter the file for the wanted line instead of searching through each line (and much faster, especially with big files):
for /f "tokens=2 delims== " %%A in ('type gdb.txt^|findstr /bic:"arg = "') Do set "var=%%A"
echo arg is %var%.
Note: should there be more than one matching line, this will give you the last result.

#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q64803488.txt"
SET "arg="
FOR /f "usebackq tokens=1-3" %%a IN ("%filename1%") DO (
IF /i "%%a"=="arg" IF "%%b"=="=" SET "arg=%%c"
)
ECHO arg found was "%arg%"
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I used a file named q64803488.txt containing your data for my testing.
The usebackq option is only required because I chose to add quotes around the source filename.
Set arg to empty to ensure it isn't already set.
For each line in the file, tokenise using the default delimiter set (which includes space) and select the first 3 tokens. If the first (%%a) is arg (/i to make case-insensitive) and the second in %%b is = then assign the third (%%c) to arg.

If I was doing this in a batch-file, I'd do it like this:
#For /F Tokens^=* %%G In ('%SystemRoot%\System32\findstr.exe /BIRC:"arg = [0123456789]" "gdb.txt" 2^> NUL') Do #Set /A %%G 2> NUL
#Set arg & Pause
The second line is there just to show you the results. You should replace that with your own code.
The first line could possibly be made shorter too, (although I wouldn't recommend it)!
#For /F Tokens^=* %%G In ('FindStr /BIRC:"arg = [0-9]" gdb.txt')Do #Set /A %%G

Related

Batch program - delete all dividing symbols in numbers

I have a homework task which needed to be done using just batch script. I need to rewrite all the numbers in .txt file if they have dividing symbols . or , but those strings may contain both words and numbers. Also the result should stay in the same file.
For example:
Lorem ipsum dolor 12.3254
2556,4646 ex commodo
would become
Lorem ipsum dolor 123254
25564646 ex commodo
I started with some code that looks like this:
#echo off
setlocal EnableDelayedExpansion
SET verfile=%1
FOR /f "tokens=* delims= " %%A IN (%verfile%) DO (
SET "Var=%%A"
FOR /l %%i IN (0, 1, 9) DO (
echo !Var! | findstr "."
IF %ERRORLEVEL% EQU 0 (
)
)
And now I have no idea how to continue it.
Can you help me please?
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory and filename are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "filename1=%sourcedir%\q73553463.txt"
:: remove variables starting #
FOR /F "delims==" %%b In ('set # 2^>Nul') DO SET "%%b="
SET /a linecount=0
:: Read entire file into memory
FOR /f "usebackqdelims=" %%e IN ("%filename1%") DO (
rem next line number
SET /a linecount +=1
rem record in memory
SET "#!linecount!=%%e"
)
:: process each line removing [,.] following a digit
:: and report to original file
(
FOR /L %%e IN (1,1,%linecount%) DO (
FOR %%c IN ("." ",") DO FOR /L %%y IN (0,1,9) DO SET "#%%e=!#%%e:%%y%%~c=%%y!"
ECHO !#%%e!
)
)>"%filename1%"
TYPE "%filename1%"
GOTO :EOF
The set # command will generate a list like
#whatever=something
#whateverelse=somethingelse
for all variables that are currently set and start #.BUT it would be unusual to have any variable set that starts # so set would generate an error. The 2^>nul sends any error-report (on standard device stderr, which is device 2) to nul that is, nowhere. The caret ^ is required because cmd needs to distinguish between a part of the set command and a part of the for.
The for/f...%%b using delims of = generates "tokens" from the list generated by the set. Tokens are separated by any sequence of any of the delimiters specified between = and ", and by default, "token1" is selected, so the strings applied to %%b are
#whatever
#whateverelse
and these variables need to be set to nothing.
See for /? from the prompt for documentation on for or browse thousands of examples on SO.
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces which can cause chaos. Once bitten, twice shy.
Then we read the file. Using "delims=" sets no delimiters, hence the whole line forms "token 1" which is assigned to %%e. The usebackq changes the meaning of " so that a double-quoted filename may be used. The filename I've used includes a Space but if there are no separator characters in the name, the quotes and usebackq can be omitted (again, ref for/?)
Then add 1 to the linecount and record the line in memory by assigning it to #!linecount!. The !linecount! is required because linecount is varying within the block (parenthesised sequence of lines) - and with delayedexpansion enabled, %linecount% yields the value when the block was encountered, and !linecount! the run-time or instantaneous value - as it changes within the block.
Stephan's DELAYEDEXPANSION link
So - having established #1, #2..#%linecount% with the lines from the file, we can process those variables and produce a replacement file.
Note that there is a block formed by ( for...%%e...)>filename. This allows any echoed data within the block to be redirected to the file. > redirects to a new version whereas >> would append to any existing file.
So - we iterate through all of the #linenumber lines using a for /L on %%e. For each of these, we set %%c to "." and %%y to 0 to 9 and then replace any string %%y%%c with %%y (3. gets replaced by 3 for example). Then repeat with %%c set to ",". set /? provides documentation and browsing SO examples.
But Woah, Neddie! There's a little trick here. , is a list-separator so (. ,) won't work - it will be treated as (.). Using the quotes allows cmd to read each character separately, and we need to use %%~c instead of %%c to dump the quotes.
So - take a look around. You can do a lot with batch if you're devious enough. And no doubt you'll be challenged if you present this solution. Be ready to explain it. A really good way to follow what's happening is to turn echo on and watch the magic step-by-step. Use pause liberally and perhaps remove the >"%filename1%" to prevent the report going to the file while you're observing what's happening.
#echo off
setlocal enabledelayedexpansion
set "verfile=%~1"
echo before:
type "%verfile%"
for /f "usebackq tokens=*" %%a in ("%verfile%") do (
set strline=%%a
set strline=!strline:.=!
set strline=!strline:,=!
echo !strline!>>"%verfile%.tmp"
)
echo.
echo after:
type "%verfile%.tmp"
del /f /q "%verfile%.tmp"

Remove lines from hosts file with batch if already exists

I have a batch script to add new entries based on the given IP address:
#echo off
SET NEWLINE=^& echo.
set /p ipAddress=What is the IPv4 address of the instance?
FIND /C /I "storage.app.lab" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO %NEWLINE%^%ipAddress% storage.app.lab>>%WINDIR%\System32\drivers\etc\hosts
FIND /C /I "home.app.lab" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO %NEWLINE%^%ipAddress% home.app.lab>>%WINDIR%\System32\drivers\etc\hosts
FIND /C /I "api.app.lab" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO %NEWLINE%^%ipAddress% api.app.lab>>%WINDIR%\System32\drivers\etc\hosts
pause
However, I want to be able to overwrite existing entries with the domain name if a new ip address is entered. For example, if an entry with the domain name of "storage.app.lab" already exists, replace it with the new IP address.
How can I achieve that without using a backup hosts file?
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q64587777.txt"
:: I'll just use a fixed string for the IPaddress
set "IPaddress=User-input IP address"
:: remove variables starting #
FOR /F "delims==" %%a In ('set # 2^>Nul') DO SET "%%a="
FOR /f "tokens=1*delims=:" %%a IN (
'findstr /v /N /L /C:"storage.app.lab" /C:"home.app.lab" /C:"api.app.lab" "%filename1%"'
) DO set "#%%a=%%b"
(
FOR /F "tokens=1*delims==" %%a In ('set # 2^>Nul') DO echo %%b
for %%a in ("storage.app.lab" "home.app.lab" "api.app.lab") do echo %IPaddress% %%~a
)>"%filename1%"
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.
I used a file named q64587777.txt containing some dummy data for my testing.
The first few lines simply establish filename variables for testing, and a recognisable string to save re-entering data in testing.
The procedure will use variables named #* for temporary storage of the "other" lines in the file in question, so first clear out any variables that may exist that start #.
Then execute findstr and "print" lines that do NOT contain (/V) any of the /L literal strings provided as /c:"string-to-EXclude" and /N number thos lines with a leading serial number followed by a colon.
The for /f tokenises the line using the : separator as a delimiter and assigning the line number to %%a (token 1) and the remainder of the line (the data in question) to %%b. Set the environment variable #%%a to the lines found.
Then use the same principle on a set # list, which will list all variables starting # in the format #1=line one, delimiting on = and selecting the 2nd token, which is the line data originally read from the file.
And add the three new lines by construction.
Parenthesising the two for statements together gathers the echoed output which is then redirected to the original file, overwriting it.
Note that OP's code appended the (up to) three new lines. The requirement is (apparently) that the 3 lines will appear in the file, replacing any existing data for those three entries.

Changing a flag in the ini file from batch script

I have a script which will check if the file names and the content of the files are same or not, below is the code and it is working fine
ECHO OFF
CLS
for %%i in (C:\Users\f1ym41a\Documents\deep\*.DAT) do (
fc C:\Users\f1ym41a\Documents\deep\MOVE.DAT %%i > NUL
if errorlevel 1 (
CALL :error
echo C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are different >>output.log
) ELSE (
CALL :next
echo C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are same >>output.log
)
timeout 5
)
PAUSE
What i need to do is if the file names are same then it will change the flag in the ini file to 1. Below is the ini file (deep.ini)
[INI]
flag = 0
Since i am new to batch scripting. Can somebody help me out with this?
You can try with replacer.bat:
call replacer.bat move.dat "flag = 0" "flag = 1"
This is an easy to achieve task with using JREPL.BAT written by Dave Benham which is a batch file / JScript hybrid to run a regular expression replace on a file using JScript.
#echo off
if not exist "%USERPROFILE%\Documents\deep\MOVE.DAT" goto :EOF
if not exist "%~dp0jrepl.bat" goto :EOF
call "%~dp0jrepl.bat" "^(flag *= *)0" "$11" /F "%USERPROFILE%\Documents\deep\MOVE.DAT" /O -
The batch file first checks if the file to modify exists at all and immediately exits if this condition is not true, see Where does GOTO :EOF return to?
The batch file JREPL.BAT must be stored in same directory as the batch file with the code above. For that reason the batch file checks next if JREPL.BAT really exists in directory of the batch file and exits if this condition is not true.
The meaning of the regular expression search string is:
^ ... find at beginning of a line
(...) ... a string referenced in replace string with $1 to keep this part of found string unmodified
flag ... case-sensitive the string flag
 * ... with 0 or more spaces
= ... and an equal sign
 * ... and once more 0 or more spaces
0 ... and the character 0.
The replace string back-references the found string between beginning of line and character 0 with $1 and replaces 0 by 1.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains also %~dp0 ... drive and path of argument 0 which is the batch file path always ending with a backslash.
echo /?
goto /?
if /?
jrepl.bat /?
:: 1st need remove some possible space in the string to got more precision
when compare them: "flag = 0" will became "flag=0", no
space and no tab.
:: 2nd for to do this, use this "' (2 characters) to set a variable that
use "=" to string instead a special character,
by set "'=flag=0" (very old technical!)
:: 3rd treat equal, treat tab character, and to remove it, because some time
this is a invisible and possible character that can eventually occur
in file dat, see in this question 10878138
:: 4th Compare the strings by string from file by file, line by line...
:: finely You need replace line in the file (.dat or .ini) this part I´m really confuse, but the code are above, sorry if my error!
Obs: use the conversion of this "flag = 0" this this one "flag=0", only for processing comparatives operation, wend the %%i match flag = 0 then only changed to replace to files by flag = 1, bat, a specific thing here is the command fc are comparing %%i, by the same file in looping for with no other file.
#echo off && setlocal EnableExtensions EnableDelayedExpansion
set "'=flag=0"
set _file_new_flag1="%temp%\Flag1.dat"
set _path_to_dats=C:\Users\f1ym41a\Documents\deep\
for /f "delims= " %%T in ('forFiles /p "." /m "%~nx0" /c "cmd /c echo(0x09"') do set "_tab=%%T"
type nul >output.log && set "_tab=%_tab:~0,1%"
cd /d "!_path_to_dats!"
for /f "tokens=* delims= " %%x in ('dir /o-d /on /b "*.dat"') do (
if defined _file_new_flag (
move /y "!_file_new_flag1!" "!_file_now!"
set _file_now=<nul
set "_file_now=%%~x"
) else (
set "_file_now=%%~x"
)
call :_file_compare_:
)
endlocal & goto :_end_of_file_:
:_file_compare_:
for /f "tokens=* delims= " %%X in ('type "!_file_now!"') do (
for /f "tokens=* delims= " %%i in ('echo/"%%~X"') do (
set "_to_compare=%%~i"
call set "_to_compare=!_to_compare: =!"
for /f "tokens=* delims=" %%I in ('echo/%_tab%') do call set "_to_compare=!_to_compare:%%I=!"
if ["!_to_compare!"] equ ["%'%"] (
echo/C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are same >>output.log
echo/%%~i>>!_file_new_flag1!
) else (
echo/C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are different >>output.log
echo/flag = 1>>!_file_new_flag1!
)
timeout /t 5
set _to_compare=<nul
)
)
exit /b
:_end_of_file_:
So sorry about my English.

print specific lines from a batch file

I am trying to print Line 4, Col 21-50 out of a text file, can this be simply done under Windows somehow? I've been trying to do this:
FOR /F "usebackq tokens=1 delims=-" %G IN (%COMPUTERNAME%.txt) DO ECHO %G
This is just working out terribly. Can't I just print a specific set of lines?
I need this script to be run on multiple computers, ideally I'd like to convert it to a variable for use with slmgr -ipk, maybe someone has a better suggestion?
Contents of text file (I want the XXXXX-XXXXX-XXXXX-XXXXX-XXXXX portion):
==================================================
Product Name : Windows 7 Professional
Product ID : 00371-OEM-9044632-95844
Product Key : XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
Installation Folder : C:\Windows
Service Pack : Service Pack 1
Computer Name : LIBRA
Modified Time : 6/4/2015 7:26:54 PM
==================================================
if you want only the "Product Key" line you can try with
type %COMPUTERNAME%.txt|find /i "Product Key"
or
for /f "tokens=2 delims=:" %%# in (' type %COMPUTERNAME%.txt^|find /i "Product Key"') do echo %%#
For the task at hand, npocmaka's answer is the best suitable approach, as it does not insist on a fixed position of the string to extract from the file.
However, I want to provide a variant that sticks to a certain position.
The following code extracts the string placed at columns 21 to 50 in line 4 of file list.txt (the result is echoed (enclosed in "") and stored in variable LINE_TXT (without ""):
#echo off
for /F "tokens=1,* delims=:" %%L in (
'findstr /N /R ".*" "list.txt"'
) do (
if %%L equ 4 (
set "LINE_TXT=%%M"
goto :NEXT
)
)
:NEXT
if defined LINE_TXT set "LINE_TXT=%LINE_TXT:~20,29%"
echo."%LINE_TXT%"
The goto :NEXT command terminates the for /F loop at the given line; this is not mandatory but will improve performance for huge files (as long as the given line number is quite small).
To be more flexible, the following code can be used (define the string position in the initial set block):
#echo off
rem Define the string position here:
set FILE_TXT="list.txt"
set LINE_NUM=4
set COL_FROM=21
set COL_UPTO=50
setlocal EnableDelayedExpansion
set /A COL_UPTO-=COL_FROM
set /A COL_FROM-=1
for /F "tokens=1,* delims=:" %%L in (
'findstr /N /R ".*" %FILE_TXT%'
) do (
if %%L equ %LINE_NUM% (
set "LINE_TXT=%%M"
if defined LINE_TXT (
set "LINE_TXT=!LINE_TXT:~%COL_FROM%,%COL_UPTO%!"
)
goto :NEXT
)
)
:NEXT
endlocal & set "LINE_TXT=%LINE_TXT%"
echo."%LINE_TXT%"
Both of the above code snippets rely on the output of findstr /N /R ".*", which returns every line that matches the regular expression .*, meaning zero or more characters, which in turn is actually true for every line in the file; however, the switch /N defines to prefix each line with its line number, which I extract and compare with the originally defined one.
Here is another variant which uses for /F to directly loop through the content (lines) of the given text file, without using findstr:
#echo off
for /F "usebackq skip=3 eol== delims=" %%L in (
"list.txt"
) do (
set "LINE_TXT=%%L"
goto :NEXT
)
:NEXT
if defined LINE_TXT set "LINE_TXT=%LINE_TXT:~20,29%"
echo."%LINE_TXT%"
This method has got the better performance, because there is the skip option which skips parsing of and iterating through all lines (1 to 3) before the line of interest (4), opposed to the findstring variant.
However, there is one disadvantage:
for /F features an eol option which defines a character interpreted as line comment (and defaults to ;); there is no way to switch this option off as long as delims= defines no delimiters (last position in option string), which is mandatory here to return the line as is; so you have to find a character that does not appear as the first one in any line (I defined = here because your sample text file uses this as header/footer character only).
To extract a string from line 1, remove the skip option as skip=0 results in a syntax error.
Note that goto :NEXT is required here; otherwise, the last (non-empty) line of the file is extracted.
Although for /F does not iterate any empty lines in the file, this is no problem here as the skip option does not check the line content and skip over empty lines as well.
Finally, here is one more approach using more +3 where no text parsing is done. However, a temporary file is needed here to pass the text of the desired line to the variable LINE_TXT:
#echo off
set LINE_TXT=
more +3 "list.txt" > "list.tmp"
set /P LINE_TXT= < "list.tmp"
del /Q "list.tmp"
if defined LINE_TXT set "LINE_TXT=%LINE_TXT:~20,29%"
echo."%LINE_TXT%"
exit /B 0
This method avoids for /F and therefore the problem with the unwanted eol option as mentioned in the above solution. But this does not handle tabs correctly as more substitutes them with spaces (8 indent spaces as per default and configurable by the /Tn switch where n is the number of spaces).

extracting specified match from find/findstr results

so this is related to
compare #defines in two C files using a batch file
but different:
System is Win 7(no Linux commands).
I have 2 files with content like
Fil1.c
#define V1 6
...
int Var[V1] ;
******************************
Fil2.c
ifdef USE_V1
#define V1 6
#else
#define V1 5
#endif
I need to compare V1 with V2 in a batch file, and throw an error if they don't match.
The solution
for /f "tokens=3" %%A in ('find "#define V1" "Fil1.c"') DO (
set Var1=%%A)
for /f "tokens=3" %%A in ('find "#define V1" "Fil2.c") DO (
set Var2=%%A)
if "%VAR1%" neq "%VAR2%" goto Error2
works well when USE_V1 preprocessor is set to 0.However, when set to 1, V1 in File2.c still reads value 5 ,as findtsr finds 2 occurrences of #define , and gets the last one.
Is there a way for findstr to read only 1st or second occurrence of #define ( which I can specify based on GOTO, wherein I read USE_V1 defined in VS project xml and decide which findstr I need to execute, that which reads first occurence or that which reads second one.)
For example, I can try :
TYPE nul >%tmpPth%
findstr /N /C:"#define V1" "Fil2.c" > %tmpPth%
writes following to tmp.txt
46:#define V1 6
49:#define V1 5
but then, I should be able to read token 3 using find/findstr either from first line or second line.
I have seen solutions on stack overflow ([Batch file to output last line of findstr2) that read/print only last occurrence of
search string but I need solution where I can probably choose which line out of the matched results I need to re-run the search for, and not just print but extract tokens out of the line result.
Update: I was able to do following:
set USE_V1="0"
for /f "delims= " %%A in ('findstr /C:"USE_V1" %VCProjPath%') DO (
set USE_V1="1")
set Var3="0"
for /f "tokens=3" %%A in ('find "#define V1" "Fil1.c"') DO (
set Var1=%%A)
if %USE_V1% equ "1" goto USE_V1_USED
for /f "tokens=3" %%A in ('find "#define V1" "Fil2.c"') DO (
set Var2=%%A)
goto MOVEON
:USE_V1_USED
TYPE nul >%tmpPth1%
findstr /C:"#define V1" "Fil2.c" > %tmpPth1%
for /f "tokens=3 delims= " %%A in ('findstr /C:"#define V1" %tmpPth1%') Do (
set Var2=%%A
if "%VAR2%" neq "%VAR3%" goto MOVEON
)
:MOVEON
if "%VAR1%" neq "%VAR2%" goto Error0
The problem i face is that supposing #define V1 match in File1.c and File2.c and
findstr /C:"#define V1" "Fil2.c" > %tmpPth1%
writes to tmp file as
#define NUMATTR1MEMS 6
#define NUMATTR1MEMS 5
which when read using
for /f "tokens=3 delims= " %%A in ('findstr /C:"#define V1" %tmpPth1%') Do (
set Var2=%%A
if "%VAR2%" neq "%VAR3%" goto MOVEON
)
give op with %VAR2% from both files as
As seen, the second value corresponding to first line read from temp file has extra blank spaces ,so, even though values match numerically, the command to match these fails.
So, is there a way to redirect findstr op to text file without extra blanks at line endings?
Thanks
sedy
Let us go through the quite huge amount of tasks step by step...
At first, let's concentrate on retrieving the definition of USE_V1. As far as I understand, you have a project definition file that contains USE_V1; if USE_V1 is present in that file literally, it is considered as defined, otherwise not.
The following code snippet seeks USE_V1 and sets %VVALGLOB% if found (I place a couple of set statements for initially setting up everything at one place for convenience):
#echo off
rem global project definitions
set FILEPROJ="\path\to\project\file"
set VNAMGLOB=USE_V1
set VVALGLOB=
rem seek %VNAMGLOB% in project file and set %VVALGLOB% if found
for /F %%A in ('findstr /L /I "%VNAMGLOB%" %FILEPROJ%') do (
set VVALGLOB=1
)
The next thing is to extract the value of variable V1 from Fil1.c. Here I assume that always the first occurrence of the #define directive is the one to regard:
rem definition of data of file 1
set FILE1="Fil1.c"
set VNAM1=V1
set VVAL1=
rem processing file 1, always take FIRST occurrence of "#define"
for /F "tokens=3" %%A in ('findstr /R /I /C:"^ *#define *%VAR1%" %FILE1%') do (
set /A "VVAL1=%%A"
goto :CONT1
)
:CONT1
I used set /A rather than set here to treat the gathered value as a number.
Now let's extract the value of V1 from Fil2.c conditionally: Here I check whether or not %VVALGLOB% is defined (remember it is when USE_V1 has been defined); if it is, the first occurrence of the #define directive is taken; otherwise, the last one is checked:
rem definition of data of file 2
set FILE2="Fil2.c"
set VNAM2=V1
set VVAL2=
rem processing file 2, take FIRST OR LAST occurrence of "#define" conditionally
for /F "tokens=3" %%A in ('findstr /R /I /C:"^ *#define *%VAR2%" %FILE2%') do (
set /A "VVAL2=%%A"
if defined VVALGLOB goto :CONT2
)
:CONT2
Alternatively, if only the first or second occurrence of #define is relevant, which is the case when there are more than two such directives, the for /F portion of the code must be replaced by the following lines:
rem processing file 2, take FIRST OR SECOND occurrence of "#define" conditionally
for /F "tokens=3" %%A in ('findstr /R /I /C:"^ *#define *%VAR2%" %FILE2%') do (
if defined VVAL2 (
set "VVAL2=%%A"
goto :CONT2
)
set /A "VVAL2=%%A"
if defined VVALGLOB goto :CONT2
)
:CONT2
Having extracted the correct values from the two files, we need to compare them. For this, I assumed that they must not equal zero to be considered as valid. If one or both are zero, or if they are not equal, a message is thrown and the batch script is exited; otherwise, the batch script continues executing:
rem compare found values for equality in a NUMERICAL manner (both != 0)
if %VVAL1% neq 0 if %VVAL2% neq 0 if %VVAL1% equ %VVAL2% goto :MOVEON
echo They don't match! & exit /B
:MOVEON
rem ...
Since there are no double-quotes around all the values, a numerical comparison is done rather than a string comparison. Hence any trailing spaces do not matter.
Notes:
I added the /I switch to all findstr occurrences in order to do case-insensitive searches. However, if all the variable names like V1 are case-sensitive, just remove it.
For searching the #define directive, I established a regular expression rather than a literal search string, telling findstr to allow leading spaces and more than one space between the keyword and the variable name.
As already mentioned in the above I treat variable (V1) values of zero as invalid to avoid trouble with values other than integers. For instance, if V1 is a string abc in your file, the batch script reads 0.

Resources