Search code examples
for-loopbatch-filefindstrunc

Findstr too slow on UNC batch script


I am running a script that goes through network folders and saves the found files, however it is taking too long to run. I have tried isolating the findstr to a single folder and it runs at an okay time, so I assume it has something to do with the FOR loop.

@echo off

setlocal

set SERVERS=server1 server2 server3 server4

cls
echo Type below the query parameters:
set /p year=Year (4 digits): 
set /p month=Month (2 digits): 
set /p day=Day (2 digits): 
set /p query=Query string: 
cls
echo Results:
del /F /Q "C:\Users\%USERNAME%\Desktop\found_files\*" 2>nul
if not exist "C:\Users\%USERNAME%\Desktop\found_files" mkdir "C:\Users\%USERNAME%\Desktop\found_files"
for /f "tokens=*" %%a in ('for %%i in ^(%SERVERS%^) do @findstr /S /I /M /C:"%query%" "\\%%i\folder_structure\*%year%-%month%-%day%*.xml"') do copy /Y "%%a" "C:\Users\%USERNAME%\Desktop\found_files" >nul & echo %%a & set found=1
echo.
if "%found%"=="1" (
    echo File^(s^) saved successfully!
) else (
    echo No files found!
)
echo.
pause
if "%found%"=="1" explorer C:\Users\%USERNAME%\Desktop\found_files

Solution

  • Your script is already optimized pretty well. I don't think there is much you can do to speed things up.

    I suspect your problem is that FINDSTR is running on your local machine, and it must scan the files on all UNC paths (almost surely not local). This means the entire content of every file must be transmitted across your network. If your system is anything like where I work, that could be a nightmare. Our network drive performance is pathetic (more than a factor of 100 slower than local drive)!

    Squashman (and SomethingDark) were somewhat concerned about your outer FOR /F executing a nested FOR statement. But I believe that is the most efficient way. When FOR /F iterates command output, it must launch a new process to execute the command. Your current script only needs one sub-process.

    The more "traditional" approach would be to move the %SERVERS% iteration outside the inner loop as follows:

    for %%i in (%SERVERS%) do for /f "tokens=*" %%a in (
      'findstr /S /I /M /C:"%query%" "\\%%i\folder_structure\*%year%-%month%-%day%*.xml"'
    ) do copy /Y "%%a" "C:\Users\%USERNAME%\Desktop\found_files" >nul & echo %%a & set found=1
    

    But this is actually less efficient because it must launch a new sub-process for each UNC path within %SERVERS%. That being said, I don't think the difference is significant compared to the actual bottle neck of transmitting the file content across the network.

    To show the impact of one vs. 100 sub-processes, I ran a quick comparison of the following logically equivalent (but meaningless) commands:

    for /f "delims=" %%F in (
      'for /l %%N in ^(1 1 100^) do @findstr /m "^" *'
    ) do echo %%F>nul
    :: This took 39 seconds on my machine
    
    for /l %%N in (1 1 100) do for /f %%F in (
      'findstr /m "^" *'
    ) do echo %%F>nul
    :: This took 60.9 seconds on my machine