【问题标题】:Batch-file to recursively copy many listed files to one specific folder批处理文件以递归方式将许多列出的文件复制到一个特定文件夹
【发布时间】:2016-01-14 21:06:35
【问题描述】:

我正在尝试运行一个批处理文件,该批处理文件将递归搜索驱动器以查找我正在寻找的特定文件的列表。我相信我几乎要失望了,但递归部分有问题。

现在,我正在根据我读过的其他线程创建的两个批处理文件之间工作。

运行此批处理文件时,我希望该命令打开位于 LISTFOLDER 中的文本文件并读取此文本文件中的所有文件名。下面的脚本做得很好。以下脚本的唯一问题是它不会通过 FILESPATH 递归搜索。

@echo off

set LISTFOLDER=C:\vbk\txt\test
set FILESPATH=C:\
set DESTPATH=C:\vbk\dest\test

for /f "tokens=*" %%i in ('dir /b ^"%LISTFOLDER%\*.txt^"') do (call :COPY_FILES "%LISTFOLDER%\%%i")

pause
exit

:COPY_FILES
for %%i in (%1) do set DEST=%%~ni
for /f "usebackq delims==" %%i in (%1) do echo xcopy /qv "%FILESPATH%\%%i" "%DESTPATH%\*"

在做了更多研究后,我发现了一个通过 FILESPATH 递归搜索但不会读取文本文件的命令,它似乎是在搜索文本文件的整个路径(例如 C:\vbk\txt\test \test.txt) 与文本文件中的信息。

@echo off

set LISTFOLDER=C:\vbk\txt\test
set FILESPATH=C:\
set DESTPATH=C:\vbk\dest\test

for /f "tokens=*" %%i in ('dir /b ^"%LISTFOLDER%\*.txt^"') do (call :COPY_FILES "%LISTFOLDER%\%%i")

pause
exit

:COPY_FILES
for %%i in (%1) do set DEST=%%~ni
for /r %FILESPATH% %%I in (%1) do echo xcopy /qvs "%%I" "%DESTPATH%\*"

以下是位于 LISTFOLDER 中的 .txt 文件的一个小示例。

01PNK2.PVD
01PR52.PVD
01PVN19.PVD
01PW07S.PVD
01Q0G19.PVD
01Q0W2.PVD
01Q102.PVD
01Q182.PVD
01Q1L2.PVD
...

任何关于我如何实现这一点的建议将不胜感激。

【问题讨论】:

  • 您的子程序:COPY_FILES 中的第一个for 循环没有用;无论如何,问题是for /R 似乎只有在集合中使用通配符(*?)的情况下才能访问文件系统(即()in 之后的部分);要解决这个问题,您可以在子例程中使用以下命令行:for /R "%FILESPATH%" %%I in ("%~1*") do if /I "%~nx1"=="%%~nxI" ECHO xcopy /Q /V /S "%%~fI" "%DESTPATH%\"
  • 首先,感谢@aschipfl 的回复。我明白:COPY_FILES 是不必要的。当替换子程序行(我假设这是上面每个示例中的最后一行)并运行批处理文件时,它似乎没有做任何事情。我是做错了什么还是把你的子程序放在了错误的地方?再次感谢您的帮助。
  • 我刚刚意识到应该更改第一行for /Ffor /F "usebackq delims=" %%i in ("%LISTFOLDER%\listfile.txt") do (call :COPY_FILES "%%~i")(请注意,您需要在此处指定文本文件并且不要使用@ 987654335@!)

标签: windows batch-file recursion


【解决方案1】:

如果我做对了,下面的代码应该可以满足你的要求:

@echo off

set "LISTFOLDER=C:\vbk\txt\test"
set "FILESPATH=C:\"
set "DESTPATH=C:\vbk\dest\test"

for %%F in ("%LISTFOLDER%\*.txt") do (
    for /F "usebackq delims=" %%L in ("%%~F") do (
        for /R "%FILESPATH%" %%I in ("%%~L*") do (
            if /I "%%~nxL"=="%%~nxI" (
                ECHO xcopy /Q /V "%%~fI" "%DESTPATH%\"
            )
        )
    )
)
pause
exit /B

这就是我所做的:

  • 这里不需要子程序(:COPY_FILES),所以我省略了;
  • for /F 不接受通配符(如*?),所以我放了一个标准的for
  • for /F 循环旨在逐行读取找到的文本文件(至少根据我对您的代码的解释),因此不需要dir /B
  • 现在是棘手的部分:for /R 递归遍历目录树,搜索其集合中给定的匹配文件(即()in 之后的部分);但是,如果在那里提供了一个没有任何通配符的专用文件(如*?),它实际上不会在文件系统中搜索该文件,而只是返回树中附加该文件的所有目录;强制for /R 真正搜索您需要使用通配符的文件;所以这就是我附加*的原因;但这当然可能会返回不需要的文件,即开头包含所需名称的文件;所以我在循环内放置了一个if 语句以过滤掉相应的项目(比较的for 变量的~nx 修饰符仅扩展为纯文件名加上扩展名);
  • 由于for /R 已经完成了递归遍历目录树的工作,您不需要为xcopy 指定开关/S; (删除大写的ECHO 以实际复制文件!)
  • 您应该在批处理文件中使用exit /B 而不是exit,因为这只会在exit 也终止包含命令提示符实例(cmd) 时退出批处理文件; (这里exit /B其实是多余的,但我把它放在这里只是为了提一下......)
  • set 语法已得到改进,因此整个赋值表达式都有引号;这避免了一些特殊字符的麻烦,例如^&;请注意,"" 不会成为此处变量值的一部分;
  • 在整个脚本中修复了一些与引号相关的问题,所有路径都包含在"" 中,并且~ 修饰符用于多个for 变量以删除潜在的"" 周围;李>

【讨论】:

    【解决方案2】:

    如果您的意思是您需要将某些文本文件中列出的文件从它们在子树中的任何位置复制到特定目录,那么

    @ECHO OFF
    SETLOCAL
    :: remove variables starting $
    FOR  /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
    
    SET "sourcedir=u:"
    SET "destdir=U:\destdir"
    SET "listdir=U:\sourcedir"
    
    :: SET $num=name required from list
    :: Also maintain extlist
    SET "extlist= "
    FOR /f "tokens=1*delims=:" %%a IN (
     'type "%listdir%\q34799738*.txt" 2^>nul^|findstr /n /v /L "\"'
    ) DO (
     SET "$%%a=%%b"
     SET extlist|FIND /i " *%%~xb ">nul
     IF ERRORLEVEL 1 CALL SET "extlist=%%extlist%%*%%~xb "
    )
    
    FOR /r "%sourcedir%" %%f IN (%extlist%) DO (
     FOR  /F "tokens=1*delims==" %%a In ('set $ 2^>Nul') DO (
      IF /i "%%~nxf"=="%%b" (
       ECHO(COPY "%%f" "%destdir%\%%b"
       SET "%%a="
       SET "continue="
       FOR  /F "tokens=1*delims==" %%a In ('set $ 2^>Nul') DO SET continue=Y
       IF NOT DEFINED continue GOTO done
    
      )
     )
    ) 
    
    :done
    FOR  /F "tokens=1*delims==" %%a In ('set $ 2^>Nul') DO ECHO(NOT found : %%b
    
    GOTO :EOF
    

    您需要更改sourcedirlistdirdestdir 的设置以适应您的情况。

    我使用q34799738*.txt 过滤掉listdir 中的文本文件进行测试。

    首先,从文件中读取所有名称并将它们分配给名为 $number 的变量。文件名不会包含:,所以findstr /n 在这里可以正常工作,并对源代码进行编号。

    同时,构建所需的扩展列表。这减少了以下for /r 找到的命中。该列表的格式为 space.ext1space.ext2space... 所以 attemting to find如果列表中不存在新的 etension,space*.newextensionspace 将丢失。

    接下来,使用扩展列表扫描子树。在$ 变量集中查找匹配项。如果找到,则复制文件(该副本只是 echoed 用于测试),将 $ 变量设置为 nothing 并检查是否有任何 $ 变量未设置。如果是,请继续,如果不是,请转到 done

    在 and 处,列出所有仍设置的 $ 变量,因为未找到这些文件。

    所需的 COPY 命令仅用于测试目的ECHOed。 验证命令正确后,将ECHO(COPY 更改为COPY 以实际复制文件。附加>nul 以禁止报告消息(例如1 file copied

    【讨论】:

    • 我尝试在我的批处理文件中使用上述内容,看起来它正在工作,但实际上并没有复制文件。是否有和 echo 我需要删除才能使副本正常工作?除此之外,这似乎也可以解决我的问题。感谢您的回复!
    • 是的 - 我没有包括我的标准方向,echo( 现在完成了。
    猜你喜欢
    • 2014-10-09
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 2012-10-30
    • 2010-11-02
    • 1970-01-01
    相关资源
    最近更新 更多