【问题标题】:Batch script to copy files listed in text file from a folder and its subfolders to a new location用于将文本文件中列出的文件从文件夹及其子文件夹复制到新位置的批处理脚本
【发布时间】:2016-06-30 16:01:54
【问题描述】:

我想要一个批处理文件将文本文件中列出的所有文件从一个目标复制到另一个目标。源目标可能有多个子文件夹,我希望批处理在每个子文件夹中搜索文件名。

我不想复制文件夹本身,只复制文件。

我有以下代码,但它无法识别 (%file_list%)

set src=c:\files\sourcefolder\
set dst=c:\files\destinationfolder\
set file_list=c:\\files\files.txt

for /r "%src%" %%i in (%file_list%) do copy "%%i" "%dst%" >notcopied.txt

我还希望该文件写入一个名为“notcopied.txt”的文本文件,这样我就可以查看源文件夹中是否没有任何必需的文件。我希望将该文件写入目标文件夹。

例如:

files.txt contains
File1.pdf
File2.pdf
File3.pdf

源文件夹包含

File1.pdf
File2.pdf

notcopied.txt 将会显示

File3.pdf

感谢您的任何见解。

【问题讨论】:

  • 要从文本文件中读取你需要一个for /F循环,你的for /R循环甚至不访问文件系统(因为没有通配符;我认为这是@987654327的设计缺陷@);所以使用for /F 遍历files.txt,使用dir /B /S 递归搜索每个项目并通过另一个嵌套的for /F 循环解析其输出。如果在源中的子目录中找到文件,您要将其复制到目标中的同一子目录,还是目标平面(没有子文件夹,只有文件)?
  • 我希望它写入新文件夹而不是复制相同的子目录。
  • 那么,我提到的循环结构中的一个简单的copy 命令就可以了...

标签: batch-file


【解决方案1】:

首先,您需要启用扩展命令行

SETLOCAL ENABLEEXTENSIONS

因此您可以使用扩展的 FOR 循环。二、需要开启环境变量的延迟扩展

SETLOCAL ENABLEDELAYEDEXPANSION

这样您就可以检查是否稍后找到搜索的文件。

结果如下:

@echo off
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION

SET src=.\sourcefolder\
SET dst=.\destinationfolder\
SET file_list=.\files.txt

FOR /F %%f IN (%file_list%) DO (
    SET found=false
    FOR /F "usebackq" %%s IN (`where /R %src% %%f`) DO (
        SET found=true
        echo "%%s => %dst%\%%f"
        @copy /y "%%s" "%dst%\%%f" 
    )
    IF "!found!" == "false" (
        echo %%f is not found!
    )
)

ENABLEDELAYEDEXPANSION 在这里需要变量%found%,没有它%found% 将永远是false。 此外,要在运行时扩展环境,您必须使用!found! 语法。

你可以这样称呼它

batch.bat > result.log

结果将写入文件result.log


更新:这是不带变量 found 的 bacth 版本,并带有 @aschipfl 的建议:

@echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

SET "src=.\sourcefolder\"
SET "dst=.\destinationfolder\"
SET "file_list=.\files.txt"

FOR /F "usebackq eol=| delims=" %%f IN ("%file_list%") DO (
    rem just searching to find out existense of file
    WHERE /Q /R "%src%" "%%f"
    IF "!ERRORLEVEL!" == "0" (
        FOR /F "usebackq eol=| delims=" %%s IN (`WHERE /R "%src%" "%%f" 2^> nul`) DO (
            echo "%%s => %dst%\%%f"
            @copy /y "%%s" "%dst%\%%f" 
        )
    ) ELSE (
        echo %%f is not found!
    )
)

此版本可以处理文件名中带有space 符号的文件。
但两种解决方案都有相同的限制:sourcefolder 的名称中不能包含任何空格。出于某种原因,命令 WHERE /R "%src%" "%%f" 不起作用,而 WHERE /R %src% "%%f" 则按预期工作。


UPDATE2:这是产生result.log的版本:

@echo off
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

SET "src=.\sourcefolder\"
SET "dst=.\destinationfolder\"
SET "file_list=.\files.txt"
SET "out=.\result.log"
echo > %out%

FOR /F "usebackq eol=| delims=" %%f IN ("%file_list%") DO (
    rem just searching to find out existense of file
    WHERE /Q /R %src% "%%f"
    IF "!ERRORLEVEL!" == "0" (
        FOR /F "usebackq eol=| delims=" %%s IN (`WHERE /R %src% "%%f"`) DO (
            echo "%%s => %dst%\%%f" >> %out%
            @copy /y "%%s" "%dst%\%%f" 
        )
    ) ELSE (
        echo %%f is not found! >> %out%
    )
)

【讨论】:

  • 非常感谢您的代码!我不在我的电脑旁,但我会尽可能尝试。我应该把'> result.log'放在那个代码中的哪里来输出文件?
  • result.log 将在batch.bat的文件夹中自动创建
  • 使用where 的好主意!我认为变量found 是不必要的,因为where 在无论如何都不匹配的情况下会引发错误;你应该添加选项delims=(禁用默认分隔符spacetab)和eol=|(不使用默认字符。;)到@987654346 @ 循环...您还可以将两个 setlocal 命令合并为一个(说明两个参数)...
  • 其实变量found是必须的,因为我需要显示日志中没有找到一些文件。要删除found,有一种不同的方法,用它和你的建议更新了我的答案。
  • 1. delims== 将分隔符设置为=,因此每个包含= 的路径或文件名都会被拆分; delims= 禁用分隔符。 2. 路径或文件名也可以默认eolcharacter ;开头,所以会被忽略; | 是路径或文件名中的禁止字符,因此不会忽略任何项目...