UNC 批处理脚本上的 Findstr 太慢
Findstr too slow on UNC batch script
我正在 运行 编写一个脚本,该脚本遍历网络文件夹并保存找到的文件,但是 运行 花费的时间太长。我已经尝试将 findstr 隔离到一个文件夹中,并且它 运行s 在一个好的时间,所以我认为它与 FOR 循环有关。
@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
@echo off
set SERVERS=server1,server2,server3,server4
cls
echo Type below the query parameters:
:: Type echo %date% on command prompt if its returns the current date dd/mm/yyyy format, you can load the variables using a substring:
set year=%date:~6,4%
set month=%date:~3,2%
set day=%date:~0,2%
set /p query=Query string:
:: set counter for files founded
set found=0
cls
echo Results:
if not exist "C:\Users\%USERNAME%\Desktop\found_files" (mkdir "C:\Users\%USERNAME%\Desktop\found_files") else (del /F /Q "C:\Users\%USERNAME%\Desktop\found_files\*" 2>nul)
for /f %%i in (%SERVERS%) do ('@find /i /c "%query%" "\%%i\folder_structure\*%year%-%month%-%day%*.xml"') do (
if "%%i"=="1" (set /a found=%found%+1 && copy /Y "\%%i\folder_structure\*%year%-%month%-%day%*.xml" "C:\Users\%USERNAME%\Desktop\found_files" >nul && echo File^(s^) saved successfully! & echo.) else (echo No files found!)
)
echo.
pause
if %found% gtr 0 (explorer C:\Users\%USERNAME%\Desktop\found_files)
您的脚本已经优化得很好。我认为您可以做很多事情来加快速度。
我怀疑你的问题是 FINDSTR
在你的本地机器上是 运行,它必须扫描所有 UNC 路径上的文件(几乎肯定不是本地的)。这意味着每个文件的全部内容都必须通过您的网络传输运行。如果你的系统和我工作的地方一样,那可能是一场噩梦。我们的网络驱动器性能很差(比本地驱动器慢 100 倍以上)!
Squashman(和 SomethingDark)有点担心您的外部 FOR /F
执行嵌套的 FOR
语句。但我相信这是最有效的方法。当 FOR /F
迭代命令输出时,它必须启动一个新进程来执行命令。您当前的脚本只需要一个子进程。
更“传统”的方法是将 %SERVERS%
迭代移到内部循环之外,如下所示:
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
但这实际上效率较低,因为它必须为 %SERVERS%
内的每个 UNC 路径启动一个新的子进程。话虽如此,我认为与 t运行 通过网络发送文件内容的实际瓶颈相比,差异并不显着。
为了显示一个与 100 个子流程的影响,我 运行 快速比较了以下逻辑上等效(但无意义)的命令:
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
我正在 运行 编写一个脚本,该脚本遍历网络文件夹并保存找到的文件,但是 运行 花费的时间太长。我已经尝试将 findstr 隔离到一个文件夹中,并且它 运行s 在一个好的时间,所以我认为它与 FOR 循环有关。
@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
@echo off
set SERVERS=server1,server2,server3,server4
cls
echo Type below the query parameters:
:: Type echo %date% on command prompt if its returns the current date dd/mm/yyyy format, you can load the variables using a substring:
set year=%date:~6,4%
set month=%date:~3,2%
set day=%date:~0,2%
set /p query=Query string:
:: set counter for files founded
set found=0
cls
echo Results:
if not exist "C:\Users\%USERNAME%\Desktop\found_files" (mkdir "C:\Users\%USERNAME%\Desktop\found_files") else (del /F /Q "C:\Users\%USERNAME%\Desktop\found_files\*" 2>nul)
for /f %%i in (%SERVERS%) do ('@find /i /c "%query%" "\%%i\folder_structure\*%year%-%month%-%day%*.xml"') do (
if "%%i"=="1" (set /a found=%found%+1 && copy /Y "\%%i\folder_structure\*%year%-%month%-%day%*.xml" "C:\Users\%USERNAME%\Desktop\found_files" >nul && echo File^(s^) saved successfully! & echo.) else (echo No files found!)
)
echo.
pause
if %found% gtr 0 (explorer C:\Users\%USERNAME%\Desktop\found_files)
您的脚本已经优化得很好。我认为您可以做很多事情来加快速度。
我怀疑你的问题是 FINDSTR
在你的本地机器上是 运行,它必须扫描所有 UNC 路径上的文件(几乎肯定不是本地的)。这意味着每个文件的全部内容都必须通过您的网络传输运行。如果你的系统和我工作的地方一样,那可能是一场噩梦。我们的网络驱动器性能很差(比本地驱动器慢 100 倍以上)!
Squashman(和 SomethingDark)有点担心您的外部 FOR /F
执行嵌套的 FOR
语句。但我相信这是最有效的方法。当 FOR /F
迭代命令输出时,它必须启动一个新进程来执行命令。您当前的脚本只需要一个子进程。
更“传统”的方法是将 %SERVERS%
迭代移到内部循环之外,如下所示:
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
但这实际上效率较低,因为它必须为 %SERVERS%
内的每个 UNC 路径启动一个新的子进程。话虽如此,我认为与 t运行 通过网络发送文件内容的实际瓶颈相比,差异并不显着。
为了显示一个与 100 个子流程的影响,我 运行 快速比较了以下逻辑上等效(但无意义)的命令:
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