批处理文件以递归方式将许多列出的文件复制到一个特定文件夹

时间:2016-01-14 21:06:35

标签: windows batch-file recursion

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

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

运行此批处理文件时,我希望该命令打开位于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)vs文本文件中的信息。

@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
...

有关如何实现这一目标的任何建议将不胜感激。

2 个答案:

答案 0 :(得分:0)

如果我做对了,下面的代码应该做你想要的:

@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语句来过滤掉相应的项目(比较~nx变量的for修饰符扩展为纯文件名加上扩展名);
  • 由于for /R已经完成了递归遍历目录树的工作,因此您无需为/S指定切换xcopy; (删除大写ECHO以实际复制文件!)
  • 而不是exit,您应该在批处理文件中使用exit /B,因为这只会在exit终止包含命令提示符实例(cmd)时退出批处理文件; (这里exit /B实际上是多余的,但我把它放在这里只是为了提到......)
  • set语法已得到改进,因此整个赋值表达式周围都有引号;这可以避免使用某些特殊字符(例如^&)的问题;请注意""不会成为变量值的一部分;
  • 在整个脚本中修复了一些与引号相关的问题,所有路径都包含在""中,~修饰符用于多个for变量以消除潜在的周围环境"";

答案 1 :(得分:0)

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

@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的设置以适应您的具体情况。

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

首先,读取文件中的所有名称,并将它们分配给名为$ number 的变量。文件名不会包含:,因此findstr /n在这里工作愉快,为源代码编号。

同时,构建所需的扩展列表。这会降低以下for /r找到的匹配数。该列表的格式为 space .ext1 space .ext2 space ...所以请注意{{1如果列表中不存在新的扩展, space *。newextension space 将会错过。

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

在和,列出任何尚未设置的done变量,因为找不到这些文件。

为了测试目的,所需的COPY命令仅为$在您确认命令正确后,将ECHO更改为ECHO(COPY以实际复制文件。附加COPY以取消报告消息(例如>nul