Batch Script to stop Inner Loop when first instance of string is found

48 views Asked by At

I have a folder with a lot of sub-directories, each with a .diff file that I want to perform a search in for a specific string using a batch script. Because of our IT requirements, I do not have access to powershell. I am trying to exist my loop once my specific string is found in the file (can show up multiple times) and continue on to the next subdirectory. I have tried a few different things but none are giving me exactly what I am looking for.

The following script works a little bit, but restarts the outer loop all over again (keeps looking in the same sub-directories:

setlocal enabledelayedexpansion

REM Set the path to the folder containing subdirectories
SET folderPath=%~dp0

REM Set the specific string to search for at the beginning of a line
SET "searchString"="COMPARE DIFFERENCE FOUND AT"

REM Set the next string to search for indicating the end of content to copy
SET "endString"="EXTRA DATA SKIPPED ON TEST FILE"

REM Set the path for the output file to save the result
SET "outputFile=%folderPath%ValidationSummary.csv"
SET "output_fail=%folderPath%Validation_Fail.out"

REM Initialize a variable to track whether the start search string is found
SET "startStringFound=0"

REM Clear output file for first run
ECHO Run Name, Status > "%outputFile%"
TYPE NUL > "%output_fail%"

REM Loop through each subdirectory in the specified folder
FOR /r "%folderPath%" %%f in (*.diff) do (
    REM Initialize variables
    set "found=0"
    set "copying=0"
    set "matchingLine=0"

    REM Read each line from the file and process content between searchString and endString
    for /f "delims=" %%a in ('findstr /i /l /b /c:" COMPARE DIFFERENCE FOUND AT" "%%f"') do (
            set "matchingLine=%%a"
        set "found=1"
        set "copying=1"
        echo %%~nxf, Failed >> "%outputFile%"
        goto :continueSearch
        )
    if !found! equ 0 (
    echo %%~nxf, Passed >> "%outputFile%"
    ) else (
    continueSearch
    )
)

The following script will work, but it finds the search string each time it shows up in the file, but I want to keep the line number of the first instance and this will overwrite that:

setlocal enabledelayedexpansion

REM Set the path to the folder containing subdirectories
SET folderPath=%~dp0

REM Set the specific string to search for at the beginning of a line
SET "searchString"="COMPARE DIFFERENCE FOUND AT"

REM Set the next string to search for indicating the end of content to copy
SET "endString"="EXTRA DATA SKIPPED ON TEST FILE"

REM Set the path for the output file to save the result
SET "outputFile=%folderPath%ValidationSummary.csv"
SET "output_fail=%folderPath%Validation_Fail.out"

REM Initialize a variable to track whether the start search string is found
SET "startStringFound=0"

REM Clear output file for first run
ECHO Run Name, Status > "%outputFile%"
TYPE NUL > "%output_fail%"

REM Loop through each subdirectory in the specified folder
FOR /r "%folderPath%" %%f in (*.diff) do (
    REM Initialize variables
    set "found=0"
    set "copying=0"
    set "matchingLine=0"

    REM Read each line from the file and process content between searchString and endString
    for /f "delims=" %%a in ('findstr /i /l /b /c:" COMPARE DIFFERENCE FOUND AT" "%%f"') do (
            set "matchingLine=%%a"
        set "found=1"
        set "copying=1"
        echo %%~nxf, Failed >> "%outputFile%"
        )
    if !found! equ 0 (
    echo %%~nxf, Passed >> "%outputFile%"
    )
)

The following script stops all loops the first time the string is found (so doesn't continue searching remaining subdirectories).

setlocal enabledelayedexpansion

REM Set the path to the folder containing subdirectories
SET folderPath=%~dp0

REM Set the specific string to search for at the beginning of a line
SET "searchString"="COMPARE DIFFERENCE FOUND AT"

REM Set the next string to search for indicating the end of content to copy
SET "endString"="EXTRA DATA SKIPPED ON TEST FILE"

REM Set the path for the output file to save the result
SET "outputFile=%folderPath%ValidationSummary.csv"
SET "output_fail=%folderPath%Validation_Fail.out"

REM Initialize a variable to track whether the start search string is found
SET "startStringFound=0"

REM Clear output file for first run
ECHO Run Name, Status > "%outputFile%"
TYPE NUL > "%output_fail%"

REM Loop through each subdirectory in the specified folder
FOR /r "%folderPath%" %%f in (*.diff) do (
    REM Initialize variables
    set "found=0"
    set "copying=0"
    set "matchingLine=0"

    REM Read each line from the file and process content between searchString and endString
    for /f "delims=" %%a in ('findstr /i /l /b /c:" COMPARE DIFFERENCE FOUND AT" "%%f"') do (
            set "matchingLine=%%a"
        set "found=1"
        set "copying=1"
        echo %%~nxf, Failed >> "%outputFile%"
        goto:ExitLoop
        )
    :ExitLoop
    if !found! equ 0 (
    echo %%~nxf, Passed >> "%outputFile%"
    )
)
1

There are 1 answers

9
Stephan On

You can't use labels within a code block/loop - it tends to do very unintuitive things like ignoring following commands etc. And you can't use goto to jump within a code block/loop. Every goto breaks the loop(s) (all of them), which in turn will invalidate the following code, if it refers to any metavariables %%?)

Your inner loop then could look like:

    set "matchingLine="
    for /f "delims=" %%a in ('findstr /i /l /b /c:" COMPARE DIFFERENCE FOUND AT" "%%f"') do (
        if not defined matchingLine set "matchingLine=%%a"
    )
    if defined matchingLine (
       echo %%~nxf, Failed >> "%outputFile%"
    ) else (
       echo %%~nxf, Passed >> "%outputFile%"
    )

When you don't need the actual found line (you don't ever use it in your question), you don't even need the inner for or any of your variables (which means, you don't even need delayed expansion in this part of your code:

FOR /r "%folderPath%" %%f in (*.diff) do (
    findstr /i /l /b /c:" COMPARE DIFFERENCE FOUND AT" "%%f" && (
      echo %%~nxf, Failed >> "%outputFile%"
    ) || (
      echo %%~nxf, Passed >> "%outputFile%"
    )
)

This second snippet doesn't actually search for "the first occurrence", but for "any occurrence", but it is still faster than processing each line on its own (findstr is incredibly efficient).