Batch File If statement inside For loop - if-statement

I am having the issue where my if statement (inside a for loop), doesn't seem to cooperate. What I am trying to do is this:
Loop through a bunch of zip files and rename them 005.zip, 006.zip, 007.zip, etc.
I keep a counter, starting at 5, that determines the file number, and a prefix that is 00 in order to get 005, 006, and so on.
Once the counter reaches 10, I want the prefix to just be 0 instead of 00. So when the counter is ten, that file will be named 010.zip, and then 011.zip instead of 0010.zip, 0011.zip etc.
Here is what I have thus far:
setlocal enableextensions enabledelayedexpansion
SET /a COUNT=5
SET FILE_PREFIX=00
SET /a MAX=10
for %%f in (*.zip) do (
if !COUNT! == !MAX! (set FILE_PREFIX=0)
ren "%%f" %FILE_PREFIX%!COUNT!.zip
set /a COUNT+=1
echo !COUNT!
)
endlocal
Why doesn't the if statement work? The file renaming is working fine, it is just that if statement that doesn't change the FILE_PREFIX to 0.

The problem is that your code doesnt apply delayed expansion to the FILE_PREFIX so the value is calculated just once in the loop, at parse time; instead of being refreshed every iteration at runtime.
Just change your line to
ren "%%f" !FILE_PREFIX!!COUNT!.zip
and presto! it should work.
But once you correct it, still your method would fail for numbers above 999.
For a more robust implementation, try this alternative
SET /a count=1
for %%f in (*.zip) do (
set fn=0000!count!
echo REN "%%f" !fn:~-4!%%~xf
set /a count+=1
)
Inside the loop
the code 0000!count! appends some zeros (4 in this case) to the number; so it will follow the sequence 00001, 00002, ... 00009, 000010, 000011, ...
then !fn:~-4! removes all digits but the last N (4 in this example). So it will follow the desired sequence 0001, 0002, ... 0009, 0010, 0011, ...
and %%~xf extracts the extension (.zip in all the cases of this loop) and appends it to form the final filename. So it will follow the desired sequence 0001.zip, 0002.zip, ... 0009.zip, 0010.zip, 0011.zip, ...
This method will work for any number up to 9999. You can easily extend it to 5 o 6 or even more digits.

Related

Batch files: using the result of compare in variable?

Here is the example:
set /a "number1=1"
set /a "number2=10"
if %number1% LSS %number2% (set /a "number1=%number1%+1")
echo result=%number1%
This code displays:
result=2
Is it possible in batch file to change the if statement to something like:
set /a "number1=%number1%+(%number1% LSS %number2%)"
?
The changed code at this moment displays:
Unbalanced parenthesis.
result=1
The set /A command does not feature comparison operators.
However, there is a way to compare two numbers and to get a value of -1 if the first number is less than the second one. For this, we need to know that the logical right-shift operator >> actually performs an arithmetic shift, meaning that the value of the most significant bit, which represents the sign, is shifted in at the left, hence the current sign of the number is maintained.
So for example:
the number +10 (binary representation 00000000 00000000 00000000 00001010) shifted to the right by one bit becomes +5 (binary representation 00000000 00000000 00000000 00000101);
the number -10 (binary representation 11111111 11111111 11111111 11110110) shifted to the right by one bit becomes -5 (binary representation 11111111 11111111 11111111 11111011);
When we shift to the right by 31 (or more) bit positions, the result is 32 times the sign bit (as we have 32-bit signed integers), which results in a value of -1 for negative input values and 0 for others.
When we now apply this technique, it leads us to the following code:
set /A "number1=%number1%-((%number1%-%number2%)>>31)"
You may omit the surrounding %-signs since set /A interprets any character strings that do not represent numbers or operators as variable names anyway:
set /A "number1=number1-((number1-number2)>>31)"
This can be further simplified using the appropriate assignment operator:
set /A "number1-=(number1-number2)>>31"
So your looking for something like a function or macro you can pass the values to for assessment?
The below is a macro demonstrating the concept. It is not a complete solution, as strings should be padded so they of equal length prior to assesment
#Echo Off
Set "Compare=Set "$RV="&For %%n in (1 2)Do if %%n==2 (For /F "Tokens=1,2 Delims={}" %%G in ("!Strings!")Do ((If "%%~G" LSS "%%~H" (Set "$RV=LSS") Else If "%%~G" EQU "%%~H" (Set "$RV=EQU") Else If "%%~G" GTR "%%~H" (Set "$RV=GTR"))&Echo/%%~G !$RV! %%~H))Else Set Strings="
Setlocal EnableDelayedExpansion
rem // example usage
%Compare:$RV=Ex[1]%{one}{oneb}
%Compare:$RV=Ex[2]%{one}{one}
%Compare:$RV=Ex[3]%{oneb}{one}
%Compare:$RV=Ex[4]%{13}{02}
%Compare:$RV=Ex[5]%{02}{13}
Echo/rem // Integers need to be 0 prefixed and strings should be padded to equal length or will return false:
%Compare:$RV=Ex[6]%{2}{13}
%Compare:$RV=Ex[7]%{two}{oneplus}
Set Ex[
Below is the fully realised compare macro that Pads strings to prevent false results when string lengths differ. The macro is defined using the \n newline syntax for the sake of readablitiy, however the compound version is also included.
#Echo Off & Setlocal DISABLEdelayedexpansion
rem // Pads string with 125 characters to prevent false results when string lengths differ. If comparing strings exceeding 125 characters in length,
rem // increase length of the padding and adjust s1 and s2 Substring modification length to match the number of padding characters.
Set "PAD=00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
(Set \n=^^^
%= Newline Variable. Do not Modify. =%
)
Set Compare=Set "$RV=" ^& For %%n in (1 2)Do if %%n==2 (%\n%
For /F "Tokens=1,2 Delims={}" %%G in ("!Strings!")Do (%\n%
Set "s1=!PAD!%%~G" ^& Set "s1=!s1:~-125!" ^& Set "s2=!PAD!%%~H" ^& Set "s2=!s2:~-125!"%\n%
If "!s1!" LSS "!s2!" (Set "$RV=LSS")%\n%
If "!s1!" EQU "!s2!" (Set "$RV=EQU")%\n%
If "!s1!" GTR "!s2!" (Set "$RV=GTR")%\n%
Echo/%%~G !$RV! %%~H%\n%
)%\n%
)Else Set Strings=
Setlocal ENABLEdelayedexpansion
rem // example usages
For %%A in (one two three)Do for %%B in (three two one)Do %Compare:$RV=Ex[0]%{%%A}{%%B}
%Compare:$RV=Ex[1]%{one}{oneb}
%Compare:$RV=Ex[2]%{one}{one}
%Compare:$RV=Ex[3]%{oneb}{one}
%Compare:$RV=Ex[4]%{13}{2}
%Compare:$RV=Ex[5]%{2}{13}
Set Ex[
Endlocal & Endlocal & Goto :Eof
rem // compound version of Compare Macro:
Set "Compare=Set "$RV="&For %%n in (1 2)Do if %%n==2 (For /F "Tokens=1,2 Delims={}" %%G in ("!Strings!")Do (Set "s1=!PAD!%%~G"&Set "s2=!PAD!%%~H"&Set "s1=!s1:~-125!"&Set "s2=!s2:~-125!"&(If "!s1!" LSS "!s2!" (Set "$RV=LSS") Else If "!s1!" EQU "!s2!" (Set "$RV=EQU") Else If "!s1!" GTR "!s2!" (Set "$RV=GTR"))&Echo/%%~G !$RV! %%~H&Set "s1="&Set "s2=")) Else Set Strings="
Compare macro is case sensitive. Change the If conditions within the macro to include the /I switch if you require case to be ignored
To use the macro in the Desired context:
(%compare%{String 1}{String 2}) > Nul & If "!$RV!"=="LSS" (Echo/true)& Rem // replace Echo command within Parantheses with desired command
with Strings 1 and 2 being stand ins for whatever variables or For loop tokens you're comparing.

Ridiculous caret escape sequence when mixing FOR and FINDSTR

I've got a string verification batch that handles rudimentary regex with FINDSTR and almost called it quits today when I thought I was unable to properly escape the caret character until I added a over a dozen ^.
Fail-verification Command: stringVerifier.bat "Derpy QFail" "^^^^^^^^^^^^^^^^QFail" /R
Pass-verification Command: stringVerifier.bat "QFail Derpy" "^^^^^^^^^^^^^^^^QFail" /R
stringVerifier.bat
#echo off
REM ===== Verify Sub-String In String Script =====
REM It uses Window's native findstr.exe commandline application with simplified options and scope for checking strings instead of file strings.
REM Call this script by preceeding the commandline call with the word `call` instead of directly running it.
REM
REM Parameter 1 is the string to search through. This must be wrapped in double-quotes.
REM Parameter 2 is the search pattern, e.g., "^QWARN". This must be wrapped in double-quotes.
REM Parameter 3 should be either /R for Regular Expression search or /L for a string-literal search.
REM Parameter 4 is optional. It should be true/false or t/f for case-sensitive searches.
REM Parameter 4 behavior will default to false for case-sensitivity if left out of the commandline parameters when called.
REM
REM You can check success by exit code or if the value of %match_was_found% is true/false or if %match_found% isn't empty.
REM A false value for %match_was_found% means there's no result to check due to no match occurring.
REM A non-empty value for %match_found% always indicates success, and vice-versa.
REM These values reset every time you run this script.
REM Extract between 1 from the front and 1 from the end to strip commandline quotes
Set string_to_search=%1
Set string_to_search=%string_to_search:~1,-1%
Set search_pattern=%2
Set search_pattern=%search_pattern:~1,-1%
Set search_type=%3
Set case_sensitive=%4
IF /i "%case_sensitive%"=="t" Set case_sensitive=true
IF /i "%case_sensitive%"=="f" Set case_sensitive=false
IF /i "%case_sensitive%"=="" Set case_sensitive=false
IF "%string_to_search%"=="" echo You forgot to provide parameter one, %string_to_search%, to specify your string to search, e.g., "Start of line of this string"&&exit /b 1
IF "%search_pattern%"=="" echo You forgot to provide parameter two, %search_pattern%, to specify your search pattern, e.g., "^Start of.*string$"&&exit /b 1
IF "%search_type%"=="" echo You forgot to provide parameter three, %search_type%, to specify your search type, e.g., /R or /L&&exit /b 1
IF /i NOT "%search_type%"=="/R" IF NOT "%search_type%"=="/L" echo You didn't provide the correct third parameter, %search_type%, for /R or /L&&exit /b 1
IF /i NOT "%case_sensitive%"=="" IF NOT "%case_sensitive%"=="true" IF NOT "%case_sensitive%"=="false" echo You didn't provide the correct fourth, %case_sensitive%, parameter for true or false&&exit /b 1
Set match_was_found=
Set match_found=
Set Command_To_Run=
Set Command_Ender=
Set Command_To_Run=echo.%string_to_search%
IF NOT "%case_sensitive%"=="" IF NOT "%case_sensitive%"=="true" Set Command_Ender=/I
IF "%search_type%"=="/R" (Set Command_Ender=%Command_Ender% /R %search_pattern%) ELSE (Set Command_Ender=%Command_Ender% /C:%search_pattern%)
FOR /F "tokens=*" %%i IN (' %Command_To_Run% ^| findstr.exe %Command_Ender% ') DO Set match_found=%%i
REM Deleting all variables we don't want retained as temporary env vars.
IF "%match_found%"=="" Set match_was_found=false&&Set string_to_search=&&Set search_pattern=&&Set search_type=&&Set Command_To_Run=&&Set Command_Ender=&&Set case_sensitive=&&exit /b 1
IF NOT "%match_found%"=="" Set match_was_found=true&&Set string_to_search=&&Set search_pattern=&&Set search_type=&&Set Command_To_Run=&&Set Command_Ender=&&Set case_sensitive=
REM Comment out this line or add more script logic if you want to disable console output of the matching line
echo %match_found%
exit /b 0
Is there any way to circumvent this ridiculous escape sequence in the batch itself without generated temp files and other such annoyances for escaping regex metacharacters?
You used set variable syntax is adverse.
As without quotes the carets will be used in any SET command to escape the next character.
This line will consume half of your carets
Set search_pattern=%search_pattern:~1,-1%
You should use the extended set syntax:
set "variable=content"
But you need only to change some of your lines to reduce the total amount of carets to two.
Set "search_pattern=%~2" This takes the argument and removes also the quotes
...
IF "%search_type%"=="/R" (Set "Command_Ender=%Command_Ender% /R %search_pattern%") ELSE (Set "Command_Ender=%Command_Ender% /C:%search_pattern%")
...
FOR /F "tokens=*" %%i IN (' %Command_To_Run% ^| findstr.exe %%Command_Ender%% ') DO Set match_found=%%i
Now you only need to use
stringVerifier.bat "QFail Derpy" "^^QFail" /R
That's because the last findstr still consumes one time the carets.
This could be changed also with quotes, but then you have to change your Command_Ender variable to hold only the options, but not the search string anymore.
To inspect the code you should use at some points a set Command_Ender or set search_pattern to show the real content of your variables.
You should also have a look at delayed expansion, as delayed expansion never changes the variable content.

Making a for loop read 2 lines of a text file at a time

I have a set of folders with a txt file of the same name in each one. They're path is
C:\Test\Salford_xxx\MenuSettings.txt
C:\Test\Salford_xxx\MenuSettings.txt
C:\Test\Salford_xxx\MenuSettings.txt
Where xxx is a random 3 digit number. I want the 1st line of each of these files to be changed using a text file called input.txt, which has the path and the line thats replacing the 1st line of each file. It looks like this.
C:\TEST\SALFORD_001\MENUSETTINGS.TXT
AppName: "This needs replacing 1"
C:\TEST\SALFORD_011\MENUSETTINGS.TXT
AppName: "This needs replacing 2"
C:\TEST\SALFORD_345\MENUSETTINGS.TXT
AppName: "This needs replacing 3"
C:\TEST\SALFORD_761\MENUSETTINGS.TXT
AppName: "This needs replacing 4"
C:\TEST\SALFORD_768\MENUSETTINGS.TXT
AppName: "This needs replacing 5"
C:\TEST\SALFORD_999\MENUSETTINGS.TXT
AppName: "This needs replacing 6"
I've written a for loop that puts the path and the replacement in variables, which works:
for /F "delims=" %%a in ('findstr /R /I "Salford" Input.txt') do (set "FilePath=%%a" echo %FilePath%)
for /F "delims=" %%b in ('findstr /R /I "AppName" Input.txt') do (set "NewName=%%b" echo %NewName%)
AppName is a word that is always in the first line, so that is used to search.
Here is the script for replacing the line of each file.
set "search=Appname"
set "replace=%NewName%"
set "newfile=NewOutput.txt"
(for /f "delims=" %%i in (%FilePath%) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
))>"%newfile%"
move "%newfile%" "%FilePath%"
However the loop continues to the last item in the Salford_999 folder and just edits that file. How can i make this read the first 2 lines of input.txt, make the replacement and then loop to the next two lines and so on?
Thanks
I don't understand how your code use your specifications. For example, your "for loop that puts the path in a variable" assign all paths to the same variable, so when the for ends, the variable have the last value. Also, I don't understand where the "AppName" string literal is taken from when it is used in the findstr in the second for. Finally, what happen if there is a file that have not its corresponding line in input.txt file?
A different approach is to process the input.txt file as a series of odd/even lines, and then process each one of the files described in odd lines; this may lead to a simpler solution:
#echo off
setlocal EnableDelayedExpansion
rem Process odd and even lines from input.txt file:
set "FilePath="
for /F "delims=" %%a in (input.txt) do (
if not defined FilePath ( rem Odd line...
rem Assign each odd line to "FilePath" variable
set "FilePath=%%a"
) else ( rem Even line...
rem Process this file, if it exists
if exist "!FilePath!" (
rem Block to enclose output to new file
> newfile (
rem The first line in new file is this even line in input.txt file
echo %%a
rem Copy all lines from this file, excepting the first one
more +1 "!FilePath!"
)
move /Y newfile "!FilePath!"
)
set "FilePath="
)
)

How to write a batch script in windows to loop over files , find a pattern and replace it

I have to write a batch script that loops over files and replaces stuff. Here is a sample data from the file.
1068 1181408 META METADATA 20150618201505211
20400693 400693
30H13UC 23 00
4010 618114915
4020 3
4030 0455
4040 400
4050 0029
4070 ROck
4080 XX SMALL
4090 Worley Stone
Now I need to find the Number starting with 20 and replace the next digits frm 3rd position with 10101.
Eg: In the file the 1st number stating with 20 is the 2nd line after the line beginning with 1068.
20400693 -> 2010101
and also in 340th position in the same line.
in the same line the number in 340th positon is 400693
400693 -> 10101
This pattern may or may not occur multiple times in same file
Now I can loop over the files like
for /r %i in (*)
But how do I write out the replacement part.
#ECHO OFF
SETLOCAL
:: The directory to look for data files and to place processed files
SET "sourcedir=U:\sourcedir\t w o"
SET "destdir=U:\destdir"
:: the start of the line, and length-to-match
SET "replaceinlines=20"
SET /a lengthofmatch=2
:: Replacement text, length-to-replace, column-for secondary-replacement
SET "replaceby=10101"
SET /a replacelength=6
SET /a replacecolumn=332
:: Replace-only-if-match ?
SET "replaceifmatch=Y"
:: calculate length of second-segment-to-preserve and its start-position
SET /a seg2start=replacelength+lengthofmatch
SET /a seg2=replacecolumn-seg2start
SET /a seg3start=replacecolumn+replacelength
::
FOR /f "tokens=1*delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*" '
) DO (
FOR /f "usebackqdelims=" %%x IN ("%sourcedir%\%%a") DO SET "line=%%x"&call:process
) >"%destdir%\%%a"
GOTO :EOF
:process
:: does the start-of-line match?
CALL SET "startofline=%%line:~0,%lengthofmatch%%%"
IF "%startofline%" neq "%replaceinlines%" GOTO report
:: matched start-of-line; pick up data-to-replace
CALL SET "data1=%%line:~%lengthofmatch%,%replacelength%%%"
CALL SET "data2=%%line:~%replacecolumn%,%replacelength%%%"
::
:: Not sure about this - replace-both-regardless or replace-if-data-matches
::
IF "replaceifmatch"=="Y" IF "%data1%" neq "%data2%" GOTO report
CALL SET "line=%startofline%%replaceby%%%line:~%seg2start%,%seg2%%%%replaceby%%%line:~%seg3start%%%"
:report
ECHO(%line%
GOTO :eof
You would need to change the setting of sourcedir and destdir to suit your circumstances. Produces a new file with the same filename as the source in the destination directory. U: is my test drive.
Patching your supplied data yielded the target 400693 at column 332, ot 340 as claimed.
The pattern to match at the start of the lines is placed in replaceinlines and its length in lengthofmatch
The length of the text-to-be-replaced is 6 (replacelength) but you have a replacement string of length 5.?? (replaceby)
I look at the line as havng 4 segments - the first is the 20 and the following 6 characters, the second the space between that and the second 'to be replaced' string; the last (which I named seg3 but should be seg4 is the part which follows the second 'to-be-replaced' string.
You don't say whether the replacement is to take place only if the two 'to-be-replaced' strings match or regardless, so I supplied a switch replaceifmatch - Y means "if the two match, replace both". Setting replaceifmatch to something else will replace regardless.
Beyond that, it's a simple matter of calculating the column-positions and lengths from the data provided and using call set to apply the calculated values to the strings of interest.
You can use Windows Scripting Host to get what you want.
Create a file called say, "1.wcf", and copy/paste the following:
<job>
<script language="JavaScript">
var fso = new ActiveXObject("Scripting.FileSystemObject");
var files = new Enumerator(fso.getFolder(".").files);
var count = 0;
for (; !files.atEnd(); files.moveNext())
{
var file = ""+files.item(); // make it string
if (!file.match(/.*\.txt$/))
{ continue; WScript.echo("Found itself, skipping"); }
//WScript.echo("Replacing in " + file);
var f1 = fso.OpenTextFile(file, 1);
var text = f1.ReadAll();
f1.close();
var lines = text.split("\r\n");
for (var i = 0; i < lines.length; i++)
{
var m = lines[i].match(/^20(\d+)/);
if (m)
{
lines[i] = lines[i].replace(new RegExp(m[1], "g"), '10101');
//WScript.echo("Replaced in " + lines[i]);
}
}
var f2 = fso.OpenTextFile(file, 2);
f2.Write(lines.join("\r\n"));
f2.close();
}
WScript.echo("Replaced "+count+" files");
</script>
</job>
Then, copy this file into the folder with TXT files, and run. It will process each TXT, and if a line in the TXT file starts with 20, the rest of the adjoining digits are captured into Group 1, and then are used to replace all such digit sequences on that line.
Then, the file is re-written with the updated contents.
Your spec is a bit imprecise - position of 40 string is not as stated, and you don't state whether the spacing of the replacement line matters.
Since you tagged your question with regex, I think you will be interested in my JREPL.BAT regular expression text processing utility. It is pure script (hybrid JScript/batch) that runs natively on any Windows machine from XP onward.
This first solution simply replaces the digits following 20 and 40 with the new string, disregarding original string length. So the position of the 40 string may change (does change in your example).
#echo off
for /r %%F in (*) do call jrepl "^(1068 .*\n20)\d+( +40)\d+ *$" "$110101$210101" /m f "%%F" /o -
Here is a more complicated solution that preserves the position of the 40 string (position 332 in your example)
#echo off
for /r %%F in (*) do call jrepl "^(1068 .*\n20)(\d+ +)40\d+ *$" "$1+'10101'+Array($2.length-5+1).join(' ')+4010101" /m /j /f "%%F" /o -
This final solution assumes the line is formatted with fixed width, and both the 20 and 40 numbers have maximum length of 10. This solution preserves both the position of the numbers, and the total length of the line:
#echo off
for /r %%F in (*) do jrepl jrepl "^(1068 .*\n20)\d+ *( {322}40)\d+ *$" "$110101 $210101 " /m /f "%%F" /o -
The method below assume that there are not empty lines in the files. This point may be fixed, if needed.
#echo off
setlocal EnableDelayedExpansion
rem Set working values
set "find=20"
set "replace=10101"
rem Process all files in current folder and below it
for /F "delims=" %%a in ('dir /A-D /S /B *.*') do (
rem Read this file via redirected input
rem and create a .tmp extension copy of it via redirected output
< "%%a" (
rem Read the first line
set /P "line="
set lastLine=1
rem Find the number of the lines that start with "20"
for /F "tokens=1,2 delims=: " %%b in ('findstr /N "^%find%" "%%a"') do (
rem Copy the lines before this one
set /A lines=%%b-lastLine, lastLine=%%b
for /L %%i in (1,1,!lines!) do set /P "line=!line!" & echo/
rem Process this line as desired:
rem Get the first token in this line
set "token=%%c"
rem Get the pattern to replace removing "20" from beginning of the token
rem and replace it in the entire line
for /F %%d in ("!token:*%find%=!") do set "line=!line:%%d=%replace%!"
)
rem Copy the last replaced line
echo !line!
rem Copy the rest of lines after the last replaced one
findstr "^"
) > "%%~Na.tmp"
rem Replace the original file by the processed one
move /Y "%%~Na.tmp" "%%a" > NUL
)

Linefeed in batch regex

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.
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.
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.
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:"^ \)"