Ridiculous caret escape sequence when mixing FOR and FINDSTR

270 views Asked by At

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?

1

There are 1 answers

2
jeb On BEST ANSWER

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.