2

I have a log file which has a lot of text in no particular format. It has a particular variable 'SId' which has been assigned a lot of values as the file progressed. For example:

For the first line le=24 we have SId = 23 and then,
on second it's SId = 56, following the be = 45 which......

I am trying to create a batch file which would read through the entire file and find the last assigned value to the variable 'SId'. Is it possible?

3 Answers3

2

First, the answer on the question: Yes, it is possible.

But I think, it would be additionally interesting for everybody reading the question, how to get the last SId number. Well, it is really difficult with using just limited Windows command interpreter capabilities to get this number from a text file with unknown format of the data. For that reason this pure and poor task description was interesting for me and I took this coding challenge.

I created in C:\Temp a file Test File.log with following three lines:

For the first line we have SId = 23 and then,
the second line contains nothing interesting despite SId=x8434
;on third it's "! SId  = 56, following SId=8434which ... SId34234 ... !" SId 

The last line starts with a semicolon which is a problem on lines being parsed with FOR because of eol=; being the default resulting in ignoring such lines by default.

The last line contains also double quotes which requires delayed environment variable expansion on processing this line, and two exclamation marks which can very easily result in replacing the two ! and everything between by nothing on processing this line with delayed expansion being enabled.

The last line contains also 4 times SId. The first two SId are with varying number of spaces around the equal sign, third SId is without an equal sign and therefore to ignore, and after last SId there is just a single space.

The batch code below is commented for interested readers, with the exception of the code block for determining the number from last valid SId occurrence. That part of the code is really hard to explain for a beginner in batch programming. It is definitely easier to understand how this code part works by removing @echo off from top of the batch file, run the batch file from within a command prompt window and look on the output command lines.

The ProcessLine block with the FOR loop and the subroutine GetNumber is executed with the example Test File.log four times with the values:

  = 56, following SId=8434which ... SId34234 ... !" SId 
=8434which ... SId34234 ... !" SId 
34234 ... !" SId 
 

Note: Each Value ends with a trailing space.

The batch code for this very generally described task:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "LogFile=C:\Temp\Test File.log"
if not exist "%LogFile%" goto EndBatch

rem Use command FINDSTR to search for all lines containing case-sensitive
rem the string "SId = " without or with spaces around the equal sign and
rem at least one digit. Output by FINDSTR are the lines matching this regular
rem expression with line number and a colon at beginning because of option /N.
rem The option /N is used to make sure that no line with SId starts with a
rem semicolon as those lines would be ignored by default by FOR. The last
rem line with a string matching this simple regular expression is assigned
rem to variable LastLine. Otherwise this environment variable deleted
rem before the loop still does not exist after the loop finished.

set "LastLine="
for /F "delims=" %%I in ('%SystemRoot%\System32\findstr.exe /N /R /C:"SId *= *[0123456789]" "%LogFile%"') do set "LastLine=%%I"
if not defined LastLine goto EndBatch

rem The last line contains perhaps multiple times an equal sign and perhaps
rem even multiple "SId" (secure identifier) strings. So it is necessary to
rem process this last line really the hard way. And it is better to process
rem the line perhaps containing also double quotes or other characters with
rem a special meaning for the Windows command interpreter using delayed
rem environment variable expansion.

setlocal EnableDelayedExpansion
set "Identifier="

:ProcessLine
set "Value=!LastLine:*SID=!"
if not defined Value goto LineProcessed
if "!Value!" == "!LastLine!" goto LineProcessed

for /F "tokens=1,2" %%A in ("!Value!") do (
    set "LastID="
    if "%%A" == "=" (
        set "Number=%%B"
        call :GetNumber
    ) else (
        set "Number=%%A"
        if "!Number:~0,1!" == "=" (
            set "Number=!Number:~1!"
            call :GetNumber
        )
    )
    if defined LastID set "Identifier=!LastID!"
    set "LastLine=!Value!"
    goto ProcessLine
)
set "LastLine=!Value!"
goto ProcessLine

:GetNumber
if not defined Number goto :EOF
set "IsDigit=1"
for /F "delims=0123456789" %%I in ("!Number:~0,1!") do set "IsDigit=0"
if %IsDigit% == 0 goto :EOF
set "LastID=%LastID%%Number:~0,1%"
set "Number=!Number:~1!"
goto GetNumber

rem Pass the last found identifier from current environment with delayed
rem expansion to previous environment on restoring previous environment.

:LineProcessed
endlocal & set "Identifier=%Identifier%"
if not defined Identifier goto EndBatch

echo Last SId found: %Identifier%

rem Other command lines which process the found identifier.

:EndBatch
endlocal

The output of this batch file for example Test File.log is:

Last SId found: 8434

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 /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?

Single line with multiple commands using Windows batch file explains & operator as used on one command line.

Mofi
  • 46,139
  • 17
  • 80
  • 143
0

Without seeing the actual log file content it would be difficult to provide a robust example but generally if SId is the first string on each line, one of the following two FindStr examples may suffice:

@For /F "Tokens=1,3" %%A In ('FindStr/BRC:"SId[ ]=[ ][0-9]*" "file.log"') Do @Set "%%A=%%B"
@Echo %SId%
@Pause

@For /F "Tokens=1,3" %%A In ('FindStr/RC:"^SId\ =\ [0-9]*" "file.log"') Do @Set "%%A=%%B"
@Echo %SId%
@Pause

Your last value will be assigned to a variable named %SId%. I have used file.log as the name of your log file, adjust it as necessary. To look up the options/switches for FindStr, enter FindStr/? at the command prompt.

Compo
  • 36,585
  • 5
  • 27
  • 39
0

batch isn't really made for such things. The following depends on some things:
- there is a space between SId and = and a space after the = (can be changed with the find string)
- there is a valid delimiter (space, tab, comma, =) after the value or the value is the last thing on the line.

@echo off 
SETLOCAL EnableDelayedExpansion
for /f "delims=" %%a in ('type t.txt^|find "SId = "') do (
  set "line=%%a"
  set "line=!line:*SId =!
  set /a "last=!line:~1!" 2>nul
)
echo %last%

The trick is to remove anything from the start to (including) the search string (sadly the = can't be removed with this) and then using the rest (minus the first char, which is =) with set /a to assign the number to a variable.
There is an errormessage "missing operand" in case of a string part after the number, which is redirected to NUL.

Stephan
  • 53,940
  • 10
  • 58
  • 91