For loop UNC批处理脚本上的Findstr太慢

For loop UNC批处理脚本上的Findstr太慢,for-loop,batch-file,findstr,unc,For Loop,Batch File,Findstr,Unc,我正在运行一个脚本,该脚本遍历网络文件夹并保存找到的文件,但是运行时间太长。我已经尝试将findstr隔离到一个文件夹中,并且它在一个合适的时间运行,所以我认为它与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

我正在运行一个脚本,该脚本遍历网络文件夹并保存找到的文件,但是运行时间太长。我已经尝试将findstr隔离到一个文件夹中,并且它在一个合适的时间运行,所以我认为它与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

你的脚本已经优化得很好了。我不认为你能做多少来加速事情

我怀疑您的问题是
FINDSTR
正在本地计算机上运行,它必须扫描所有UNC路径上的文件(几乎肯定不是本地的)。这意味着每个文件的全部内容必须通过网络传输。如果你的系统和我工作的地方一样,那可能是一场噩梦。我们的网络驱动器性能很差(比本地驱动器慢100倍多)

Squashman(和一些黑暗的人)有些担心您的外部
FOR/F
执行嵌套的
FOR
语句。但我相信这是最有效的方法。当/F的
FOR
迭代命令输出时,它必须启动一个新进程来执行该命令。当前脚本只需要一个子进程

更“传统”的方法是将
%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路径启动新的子进程。尽管如此,我认为与通过网络传输文件内容的实际瓶颈相比,差异并不显著

为了显示一个子进程与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

请不要写非英语的帖子。这也是一个纯英语的网站。不幸的是,我无法做到这一点,即使是通过重新排列它出错的代码“此时不应出现do”或“此时不应出现server1”。这段代码中的逻辑是一场灾难。@T3RR0R我不想听起来粗鲁,但如果字符串需要转义,我会抓住它,我认为Heitor提供的FOR循环有点错误:)别担心,很多人都会帮助我们,我们很快就会实现。嵌套
FOR
循环会降低代码的速度,但不一定会达到您正在经历的程度。我怀疑瓶颈在于访问UNC路径上的文件,而临时将该路径装载为网络驱动器将加快速度,但是我没有办法测试它。请记住,重定向和在每次迭代的基础上使用echo输出结果会大大降低速度。@T3RR0R-在每次迭代时重定向到nul不会有太大影响,因为打开一个文件从来不会花时间。我在一个紧循环中测试了10000个nul重定向,只花了1.6秒,而在循环外重定向一次只花了1.2秒。这是一个区别,但可能无关紧要。当使用类似于
>“file”
的东西时,迭代重定向速度会变得令人无法接受,因为每次迭代都必须重新打开并将文件重新定位到末尾。@SomethingDark-我一直认为将网络驱动器映射到UNC路径只是一种方便,或者使用不理解UNC路径的命令的路径。我怀疑这会节省任何处理时间。但我想在尝试之前我们不会知道。映射UNC路径的最简单方法是使用
PUSHD
。您的示例确实有意义,但我也想知道使用
FINDSTR/S
是否比使用
FOR/R
先迭代文件,然后使用
find
FINDSTR
@Squashman更慢?如果我认为这样做会更快
FINDSTR
在启动外部命令时存在开销的情况下导航树。虽然
FINDSTR/S
可能应该避免,因为如果驱动器上启用了短文件名,则存在一个可能导致其丢失文件的错误。我同意您的看法,这必须是网络限制和文件量。我相信我将不得不寻找其他方法来搜索它们,如果您有任何建议,我将乐意接受,感谢您的详细解释:)@GabrielVicente-不仅是文件的数量,而且每个文件的大小。我相信
FINDSTR/M
足够聪明,一旦找到匹配项就会短路。但如果没有匹配项,则必须搜索整个文件。我忘了提到,通过网络复制匹配的文件也需要时间。
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