Batch: Echo all lines from a specific variable from a .txt file

Viewed 113

I am trying to write a batch executable which finds and echo's a specific line: "Rating.RESP:" from a .txt-file eg. 'Rating.RESP: 50'. Numbers go from 0-100 and I want the console to prompt all variables and I do not want to copy it to another txt file.

Thus far I am trying to work with findstr:

for /F %%i in (data.txt) do (
echo %%i
findstr /m /c:"Rating.RSP: [0-100]"%%i  
)

Any tips? If this works I would be able to further extent the batch executable.


Based on @Gerhard 's help I made the following code:

set /p file=Drag data file in here.

echo.
for /F "delims=" %%i in ('type %file% ^| findstr /m "Rating.RESP: "') do echo %%i

The result is a list of 'Rating.RESP: ##'

Next up I'm trying to read the %%i and echo a warning when it exceeds 75 or below 25. Any idea's? I was thinking something with extracting the last two characters of the substring and check if it is within (or outside) the threshold. Don't need the help just yet, I'm trying to figure it out myself. Thanks again for the help with echoing Rating.RESP.


Sample input file:

*** Header End ***
    Level: 2
    *** LogFrame Start ***
    list: 1
    Procedure: proc
    leftanchor: Alert
    rightanchor: Suf
    XTime: 09:55:25
    list.Cycle: 1
    list.Sample: 1
    Running: list
    Scale1.RT: 2054
    Scale1.RESP: 1
    Response: t056
    Rating.RESP: 56
    *** LogFrame End ***
    Level: 2
    *** LogFrame Start ***
    list: 2
    Procedure: proc
    leftanchor: Kalm
    rightanchor: Opgewonden
    XTime: 09:55:28
    list.Cycle: 1
    list.Sample: 2
    Running: list
    Scale1.RT: 861
    Scale1.RESP: 1
    Response: t050
    Rating.RESP: 50
2 Answers

Your original question is a little ambiguous: from comments, I think "which finds and echo's a specific line: "Rating.RESP:"" would be better as "which finds and echo's a all lines containing the specific string: "Rating.RESP:"". With that assumption, and your additional comments about detecting out-of-range values, I think the following will do the trick:

alert.bat

@echo off
    setlocal
    set LOW_LIMIT=25
    set HIGH_LIMIT=75

    set /p file=Drag data file in here.

    for /f "usebackq tokens=1,2" %%a in ( `findstr "Rating.RESP: " "%file%"` ) do (
        setlocal enabledelayedexpansion
        set "WARN="
        if %%b LSS  %LOW_LIMIT% set "WARN=  ** Value too low **"
        if %%b GTR %HIGH_LIMIT% set "WARN=  ** Value too high **"
        echo %%a%%b!WARN!
    )

Presented with a file containing:

something else
something else
Rating.RESP: 10
something else
something else
Rating.RESP: 50
something else
something else
Rating.RESP: 80
something else
something else

this will produce the output:

C:>alert.bat
Drag data file in here.data.txt
Rating.RESP:10  ** Value too low **
Rating.RESP:50
Rating.RESP:80  ** Value too high **

Notes / Assumptions:

  • There is no need to type the file and pipe it into findstr: we can just give the file on the command-line.
  • Using usebackq option allows use of double-quotes (both in the string to be found and, if necessary, the filename). This isn't strictly necessary, but often prevents problems.
  • [Update] I have removed the /b from the original version of this answer as Rating.RESP doesn't always (ever?) start at the beginning of the line.
  • Using tokens=1,2 with the default delimiter (space or tab) will break matching lines into Rating.RESP (in %%a) and the numeric value (in %%b).
  • The current code assumes that lines with Rating.RESP: will only be followed by valid numbers, and that there are no leading zeroes (e.g. 07). If either of these assumptions is false, some extra code will be needed. (The problem with leading zeroes is that CMD treats them as octal, so 09 would be considered an invalid number).
  • Use of setlocal enabledelayedexpansion allows us to both set the value of WARN and use it within the body of the for command.

Enhanced Checking

If there is a need to detect invalid numbers, or to handle numbers with leading zeros, then the following will do the job:

@echo off
    setlocal
    set LOW_LIMIT=25
    set HIGH_LIMIT=75

    set /p file=Drag data file in here.

    for /f "usebackq tokens=1,2" %%a in ( `findstr "Rating.RESP: " "%file%"` ) do (
        setlocal enabledelayedexpansion
        set "WARN="
        for /f "delims=0123456789 tokens=1" %%x in ("%%b") do if not "%%x" == "" set "WARN=  ** Invalid number **"
        if not defined WARN (
            set "NUM=000%%b"
            set "NUM=1!NUM:~-3,3!"
            set /a NUM=!NUM!-1000
            if !NUM! LSS  %LOW_LIMIT% set "WARN=  ** Value too low **"
            if !NUM! GTR %HIGH_LIMIT% set "WARN=  ** Value too high **"
        )
        echo %%a%%b!WARN!
    )
~

Notes

  • The for /f "delims=0123456789 tokens=1" line detects non-digits in %%b. By using all digits as separators, a purely numeric string will set %%x to an empty string (since there is nothing but separators). However, if there are any non-digits, then the first run of them will be extracted, and %%x will no longer be empty. The rest of the main loop is only executed if this didn't generate a warning.
  • When working with numbers (e.g. SET /A, or IF ... GTR ... etc.), batch-files treat leading zeros as octal: 010 would be treated as 8. To allow leading zeros in decimal numbers, we:
    • First create NUM with "sufficient" leading zeros. 08 would become 00008; 100 would become 000100 etc.
    • The expression !NUM:~-3,3! takes the last three characters of NUM. Because of the preceding step, this will always be zero-padded (00008 -> 008; 000100 -> 100). The value of NUM is replaced by 1 followed by these three characters (e.g. 1008 or 1100).
    • Now that there are no leading zeroes, we use SET /A to reduce the value by 1000 (e.g. 8 or 100). This can now be used safely in the limit tests.

With an input file of:

    Rating.RESP: 15
    Rating.RESP: 85
    Rating.RESP: 09
    Rating.RESP: 026
    Rating.RESP: 26
    Rating.RESP: xx
    Rating.RESP: 9x
    Rating.RESP: x9

we now get:

Rating.RESP:15  ** Value too low **
Rating.RESP:85  ** Value too high **
Rating.RESP:09  ** Value too low **
Rating.RESP:026
Rating.RESP:26
Rating.RESP:xx  ** Invalid number **
Rating.RESP:9x  ** Invalid number **
Rating.RESP:x9  ** Invalid number **

(With the original version, 026 would have been treated as octal, becoming 22 decimal, and would have triggered the "too low" warning).

Here's how I'd do that, if I wasn't looking to only return instances followed by numbers 0 through 100.

@Find "Rating.RSP:"<"data.txt"

It could also be made case insensitive if required:

@Find /I "Rating.RSP:"<"data.txt"

[Edit /] Update due to modified/extended question

@Set /A Lo=25,Hi=75
@Set "_="&Set /P "_=Drag file here >"
@If Defined _ For /F "Tokens=2Delims=:" %%A In ('Find "Rating.RESP: "^<"%_%"'
)Do @If %%A Lss %Lo% (Echo Value too low:%%A
)Else If %%A Gtr %Hi% Echo Value too high:%%A
@Pause
Related