2

I want to match all lines of the following text with FINDSTR /R

LABO_A =
  (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))
    (CONNECT_DATA =
      (SERVICE_NAME = LABO)
    )
  )

I already tried What are the undocumented features and limitations of the Windows FINDSTR command? Especially the "Searching across line breaks" part. But unfortunately it didn't work.

My approach is the following:

SETLOCAL
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"

SETLOCAL enableDelayedExpansion
FINDSTR /R "LABO_A.=.!CR!*!LF!.*(DESCRIPTION.=.!CR!*!LF!.*(ADDRESS.=.(PROTOCOL.=.TCP)(HOST.=.host01)(PORT.=.1521))!CR!*!LF!.*(CONNECT_DATA.=!CR!*!LF!.*(SERVICE_NAME.=.LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH%

Am I missing something? Or is the batch regex simply not powerful enough to realize this?

SOLUTION: The approach of @dbenham let me reconsider my regex-string. So I edited it to

FINDSTR /R /C:"LABO_A =!CR!*!LF!.*(DESCRIPTION =!CR!*!LF!.*(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF!.*(CONNECT_DATA =!CR!*!LF!.*(SERVICE_NAME = LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH% > NUL

I removed some unnecessary white spaces and adapted the parameters of FINDSTR.

Now it works.

Community
  • 1
  • 1
Marco Frost
  • 780
  • 3
  • 12
  • 25

3 Answers3

2

Your regex is wrong. Your source lines end immediately after the =, but the extra . in your regex is looking for an additional character after the =.

It looks to me you are using . to represent white space. I think you would be better off using actual spaces, but then you need the /C option.

The following matches the lines successfully.

@echo off
SETLOCAL
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"

SETLOCAL enableDelayedExpansion
FINDSTR /R /C:"LABO_A =!CR!*!LF! *(DESCRIPTION =!CR!*!LF! *(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF! *(CONNECT_DATA =!CR!*!LF! *(SERVICE_NAME = LABO)!CR!*!LF! *)!CR!*!LF! *)" test.txt

Note that even though all lines in the regex are matched, only the first line of the matching set is printed.

I suspect that the line breaks are not required in your configuration file. Here is another variation that allows for more variation in the white space.

@echo off
setlocal enableDelayedExpansion
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"
set "ws=[ !cr!!lf!]*"

FINDSTR /RX /C:"LABO_A =!ws!(DESCRIPTION =!ws!(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!ws!(CONNECT_DATA =!ws!(SERVICE_NAME = LABO)!ws!)!ws!)!ws!" test.txt

I also attempted to allow white space in every place I thought possible, but that exceeded FINDSTR's maximum REGEX string length.

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Thank you for your effort, but unfortunately both approaches don't work for me. I don't get a single match. :( – Marco Frost Nov 11 '13 at 11:05
  • @MarcoFrost - Your data must not match what you posted. I tested with your posted data, and both solutions above matched just fine. – dbenham Nov 11 '13 at 12:07
  • Okay. As you can see, I've added the solution to my post. Your answer helped me - after all - very well. – Marco Frost Nov 11 '13 at 12:37
1

Essentially, batch regex isn't powerful enough. SED would be better no doubt.

Nonetheless, here's a way to detect that a sequence of lines appears in a file. It's a little restricted, but should suffice for the sequence you've nominated. It assumes that leading spaces are not significant.

@ECHO OFF
SETLOCAL enabledelayedexpansion
FOR /f "delims==" %%a IN ('set l_ 2^>nul') DO "SET %%a="
SET /a lines=0
FOR /f "tokens=*" %%a IN (q19859936.txt) DO SET /a lines+=1&SET l_!lines!=%%a

SET hits=0
SET "stop="
FOR /f "tokens=*" %%a IN (q19859936.test) DO (
 SET l_0=%%~a
 CALL :test
 IF DEFINED stop GOTO done
)
:done
IF DEFINED stop (ECHO FOUND ) ELSE (ECHO NOT FOUND)

GOTO :EOF

:test
SET /a hits+=1
ECHO IF NOT "!l_%hits%!"=="%l_0%" 
IF NOT "!l_%hits%!"=="%l_0%" SET hits=0&IF %hits%==1 (GOTO :eof) ELSE (GOTO test)
IF %hits%==%lines% SET stop=Y
GOTO :eof

[edited code 20131111T1408Z - first FOR had tokens=2]

The initial FOR ensures that variables L_* are cleared.

The file q19859936.txt is read as the line-sequence-to-be-detected data.

q19859936.test is then examined. Each line is assigned to L_0 in turn and the internal subroutine :test will check to see whether it matches the next-line-expected.

The IF NOT statement is significant - and seemingly illogical (you'd need to add the /i switch to make it case-insensitive if you so want...) When batch parses the line, %hits% is replaced by the then-current value of hits and THEN the line is executed, so hits will be reset to 0 if ever a mismatch is found. If the HITS count WAS not 1, then the test is repeated. This takes care of the case

matches line 1
matches line 2
matches line 3
matches line 1
matches line 2
matches line 3
matches line 4
matches line 5
matches line 6

where the second "line 1" is encountered when "line 4" was expected. HITS is thus changed to 0, but it WAS 4 so execution passes back to :test and the test repeated with HITS=1.

Another approach could have been to read lines into another array (say L#*) and test that L_* matched L#*, for %LINES% entries. On no match, ripple-up and assign the next line read to L#!lines! ... but I thought of that later. Probably be easier and better, too - I'll leave it as an exercise for whoever may be interested.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • I have a problem with the first FOR. When I run it a second time, the FOR-line triggers an error. It combines every single line of the testfile with the set-command and doesn't know what to do with it. For example: The command "SET )=" is either wrong or could not be found. – Marco Frost Nov 11 '13 at 13:10
  • Yes - the first `FOR` had 'tokens=2` - should be `tokens=1` (which is the default, hence can be eliminated) – Magoo Nov 11 '13 at 14:11
  • Okay. I changed it to `tokens=1`. Now i have the same error, but with `SET l_0=` and `SET l_1=` and so on. – Marco Frost Nov 12 '13 at 14:24
0

This will work if you are after the LABO_A reference.

It uses a helper batch file called findrepl.bat from - https://www.dropbox.com/s/rfdldmcb6vwi9xc/findrepl.bat

Place findrepl.bat in the same folder as the batch file or on the path.

type "file.txt" | findrepl "^LABO_A =" /e:"^  \)"
foxidrive
  • 40,353
  • 10
  • 53
  • 68
  • 1
    Not sure if this is what the OP is looking for. You only match the beginning and end, but OP may want to verify all values in between. – dbenham Nov 08 '13 at 20:05