【问题标题】:How to copy a directory structure but only include certain files (using windows batch files)如何复制目录结构但仅包含某些文件(使用 Windows 批处理文件)
【发布时间】:2010-10-03 03:05:37
【问题描述】:

正如标题所说,我如何递归地复制目录结构但只包含一些文件。例如,给定以下目录结构:

folder1
  folder2
    folder3
      data.zip
      info.txt
      abc.xyz
    folder4
    folder5
      data.zip
      somefile.exe
      someotherfile.dll

data.zipinfo.txt 文件可以出现在目录结构中的任何位置。如何复制完整的目录结构,但只包含名为 data.zip 和 info.txt 的文件(应忽略​​所有其他文件)?

生成的目录结构应如下所示:

copy_of_folder1
  folder2
    folder3
      data.zip
      info.txt
    folder4
    folder5
      data.zip

【问题讨论】:

    标签: windows batch-file cmd robocopy


    【解决方案1】:

    你没有提到它是否只能是批处理,但如果你可以使用ROBOCOPY,试试这个:

    ROBOCOPY C:\Source C:\Destination data.zip info.txt /E
    

    编辑:将 /S 参数更改为 /E 以包含空文件夹。

    【讨论】:

    • 我可以用这种语法复制 *.zip 吗?我试着只写 *.zip 而不是 data.zip,但它没有复制文件,只复制文件夹。我也试过 ?.zip
    • @Niels Brinch 是的,你应该能够做到。您使用的确切命令行是什么?
    • ROBOCOPY C:\Source C:\Destination *.zip /E
    • 很奇怪。您使用的是什么操作系统?您是否拥有必要的文件/文件夹权限?我刚刚在 Win 7 上进行了测试,*.zip 为我工作。
    • 真的!?我也在使用 Win 7。当我尝试时,它只是不复制任何文件。只有文件夹。我会再尝试。 (虽然我们在这里,但包含 *.zip 以外的语法是什么 - 比如说 *.zip 和 *.jpg。
    【解决方案2】:

    一次复制一个文件且不需要 ROBOCOPY 的替代解决方案:

    @echo off
    setlocal enabledelayedexpansion
    
    set "SOURCE_DIR=C:\Source"
    set "DEST_DIR=C:\Destination"
    set FILENAMES_TO_COPY=data.zip info.txt
    
    for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
        if exist "%%F" (
            set FILE_DIR=%%~dpF
            set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
            xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
        )
    )
    

    外部for语句生成SOURCE_DIR中的子目录和FILENAMES_TO_COPY中的名称的任何可能的路径组合。对于每个现有文件,都会调用 xcopy。 FILE_INTERMEDIATE_DIR 包含文件在SOURCE_DIR 中的子目录路径,需要在DEST_DIR 中创建。

    【讨论】:

    • 我需要复制文件夹和子文件夹中的所有照片,这个批处理脚本有帮助。刚刚把上面的set FILENAMES_TO_COPY=data.zip info.txt改成set FILENAMES_TO_COPY=*.jpg
    • 我收到一个错误,因为文件路径上有空格 (SOURCE_DIR="C:\Origin Test", DEST_DIR="C:\Dest Test", error: Test"" 是意外的此刻)。我试图将 %var% 更改为 !var!到处都是,但没有成功。关于如何解决这个问题的任何线索?整个结构充满了带有空格的文件夹名称。
    • 试试set "SOURCE_DIR=C:\Origin Test"set "DEST_DIR=C:\Dest Test"。注意双引号的位置。
    【解决方案3】:

    尝试将 find 的输出(即文件路径)传递到 cpio

    find . -type f -name '*.jpg' | cpio -p -d -v targetdir/
    

    cpio 检查目标文件的时间戳——因此它既安全又快速。

    一旦你习惯了,去掉 -v 以获得更快的操作。

    【讨论】:

    • @Christian 它依赖于不属于标准安装的 cpio。
    【解决方案4】:

    如果 Powershell 是一个选项,您可以这样做:

    Copy-Item c:\sourcePath d:\destinationPath -filter data.zip -recurse
    

    主要缺点是它会复制所有文件夹,即使它们最终会是空的,因为没有文件与您指定的过滤器匹配。因此,除了包含所需文件的少数文件夹之外,您最终可能会得到一棵充满空文件夹的树。

    【讨论】:

    • 第二次运行会改变目的地。 (它将文件放在子文件夹中。)如果您问我,这是一种愚蠢的行为。您需要在复制之前运行 rm -r -ErrorAction:SilentlyContinue d:\destinationPath 以解决此问题。
    【解决方案5】:

    将所有文本文件复制到 G: 并保留目录结构:

    xcopy *.txt /s G:
    

    【讨论】:

    • 这可以递归工作吗,比如从子文件夹复制所有 .txt 并保留相对于基本目录的目录结构?
    • @Micka 是的
    【解决方案6】:

    感谢以前的答案。 :)

    这个脚本名为“r4k4copy.cmd”:

    @echo off
    for %%p in (SOURCE_DIR DEST_DIR FILENAMES_TO_COPY) do set %%p=
    cls
    echo :: Copy Files Including Folder Tree
    echo :: http://stackoverflow.com
    rem     /questions/472692/how-to-copy
    rem     -a-directory-structure-but-only
    rem     -include-certain-files-using-windows
    echo :: ReScripted by r4k4
    echo.
    if "%1"=="" goto :NoParam
    if "%2"=="" goto :NoParam
    if "%3"=="" goto :NoParam
    setlocal enabledelayedexpansion
    set SOURCE_DIR=%1
    set DEST_DIR=%2
    set FILENAMES_TO_COPY=%3
    for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
    if exist "%%F" (
    set FILE_DIR=%%~dpF
    set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
    xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
    )
    )
    goto :eof
    :NoParam
    echo.
    echo Syntax: %0 [Source_DIR] [Dest_DIR] [FileName]
    echo Eg.   : %0 D:\Root E:\Root\Lev1\Lev2\Lev3 *.JPG
    echo Means : Copy *.JPG from D:\Root to E:\Root\Lev1\Lev2\Lev3
    

    它接受“Source”、“Destination”和“FileName”的变量。 它也只能复制指定类型的文件或选择性的文件名。

    欢迎任何改进。 :)

    【讨论】:

      【解决方案7】:

      仅使用 find 和 cp:

      mkdir /tmp/targetdir
      cd sourcedir
      find . -type f -name '*.zip' -exec cp -p --parents {} /tmp/targetdir ";"
      find . -type f -name '*.txt' -exec cp -p --parents {} /tmp/targetdir ";"
      

      【讨论】:

        【解决方案8】:

        类似于 Paulius 的解决方案,但您不关心的文件不会被复制然后删除:

        @echo OFF
        
        :: Replace c:\temp with the directory where folder1 resides.
        cd c:\temp
        
        :: You can make this more generic by passing in args for the source and destination folders.
        for /f "usebackq" %%I in (`dir /b /s /a:-d folder1`) do @echo %%~nxI | find /V "data.zip" | find /v "info.txt" >> exclude_list.txt
        xcopy folder1 copy_of_folder1 /EXCLUDE:exclude_list.txt /E /I
        

        【讨论】:

          【解决方案9】:

          这只是两个简单的命令,但我不建议这样做,除非您不需要复制的文件很小。这是因为这将复制所有文件,然后删除副本中不需要的文件。

          xcopy /E /I folder1 copy_of_folder1
          for /F "tokens=1 delims=" %i in ('dir /B /S /A:-D copy_of_files ^| find /V "info.txt" ^| find /V "data.zip"') do del /Q "%i"
          

          当然,第二个命令有点长,但它有效!

          此外,这种方法不需要您下载和安装任何第三方工具(Windows 2000+ BATCH 对此有足够的命令)。

          【讨论】:

          • 非常感谢。正如您所提到的,这并不理想,因为(在我的情况下)必须复制的文件通常很小,而不应复制的文件较大(并且可能很多)。
          【解决方案10】:

          在 Linux 和其他 UNIX 系统下,使用 tar 命令可以轻松完成此操作。

          $ tar cvf /tmp/full-structure.tar *data.zip *info.txt
          

          然后你会 cwd 到目标并且:

          $ tar xvf /tmp/full-structure.tar 
          

          当然,您可以将第一个 tar 的输出通过管道传输到第二个,但是看到它按步骤工作更容易理解和解释。我在以下命令中缺少必要的 cd /to/new/path/ - 我只是不记得现在该怎么做。希望其他人可以添加它。

          $ tar cvf -  *data.zip *info.txt |  tar xvf - 
          

          Tar (gnutar) 也可以在 Windows 上使用,但我自己可能会在那个平台上使用 xcopy 方法。

          【讨论】:

          • tar cvf /tmp/full-structure.tar **/data.zip **/info.txt 为我工作
          • “tar cvf /tmp/full-structure.tar **/data.zip **/info.txt”和“tar cvf /tmp/full-structure.tar *data.zip * info.txt”给了我3个错误:(1)“tar:*data.zip:无法统计:没有这样的文件或目录”,(2)“tar *info.txt:无法统计:没有这样的文件或目录”, (3) “tar:Exiting with failure status due to previous errors”。我从哪个文件夹做这一切?这个方法我看不懂。
          • 问题说WINDOWS
          • Win10 有 WSL,这使得它有效。 tar 已经在 Windows 上可用了 20 多年,并且自 MS-DOS 时代以来,管道的使用就一直有效。在任何 shell 环境中,PWD 都很重要。 PWD - 当前工作目录。我承认这个解决方案不太适合最终用户,而更适合高级用户或程序员。
          【解决方案11】:
          XCOPY /S folder1\data.zip copy_of_folder1  
          XCOPY /S folder1\info.txt copy_of_folder1
          

          编辑:如果您想保留空文件夹(在重新阅读您的帖子时,您似乎会这样做)使用 /E 而不是 /S。

          【讨论】:

          • 它不保留文件夹结构。
          • /E 选项保留文件夹结构,包括在必要时创建空文件夹。文件名也适用于通配符(例如 folder1\*.zip)。当我将不存在的完整文件名传递给它时,我只会收到“找不到文件错误”(在这种情况下,我会收到“找不到文件 - xxx.xxx 0 文件已复制”。当我给它一个模式时不返回任何文件(例如,folder1\*.zzz),我只得到“0 个文件(*s)已复制”。
          【解决方案12】:

          使用 WinRAR 命令行界面,您可以将文件名和/或文件类型复制到存档。然后,您可以将该存档提取到您喜欢的任何位置。这会保留原始文件结构。

          我需要将丢失的专辑图片文件添加到我的手机中,而无需重新复制音乐本身。幸好我的电脑和手机上的目录结构是一样的!

          我用过:

             rar a -r C:\Downloads\music.rar X:\music\Folder.jpg
          
          • C:\Downloads\music.rar = 要创建的存档
          • X:\music\ = 包含音乐文件的文件夹
          • Folder.jpg = 我要复制的文件名

          这创建了一个存档,其中包含正确子目录中的所有 Folder.jpg 文件。

          此技术也可用于复制文件类型。如果文件都有不同的名称,您可以选择将所有文件提取到一个目录中。额外的命令行参数可以归档多种文件类型。

          此非常有用的链接http://cects.com/using-the-winrar-command-line-tools-in-windows/中的更多信息

          【讨论】:

            【解决方案13】:

            对于那些使用Altap Salamander(2 个面板文件管理器)的用户:在复制弹出窗口的选项中,只需指定文件名或掩码。很简单。

            【讨论】:

              【解决方案14】:

              我对正则表达式很好,懒惰并且不喜欢安装,所以我创建了一个批处理文件,它创建目录并使用 vanilla DOS 命令进行复制。对我来说似乎比使用 robocopy 更费力但更快。

              1. 在文本文件中创建包含完整路径的源文件列表,包括驱动器号(如果需要)。
              2. 在文本编辑器中打开正则表达式。
              3. 在每行添加双引号以防止空格 - 搜索字符串(.*)替换字符串"\1",然后单击全部替换
              4. 每个文件创建两行 - 一行创建目录,一行复制文件(qqq将替换为目标路径) - 搜索字符串(.*)替换字符串md qqq\1\nxcopy \1 qqq\1\n并点击全部替换
              5. 从目标路径中删除文件名 - 搜索 \\([^\\^"]+)"\n 替换 \\"\n
              6. 在目标路径中替换(在本例中为A:\srcB:\dest)。关闭正则表达式,搜索qqq"A:\src\替换B:\dest\并点击全部替换。

              md 将创建嵌套目录。在本例中,copy 的行为可能与 xcopy 相同。您可能希望将 /Y 添加到 xcopy 以禁止覆盖确认。你最终会得到一个像这样的批处理文件:

              md "B:\dest\a\b\c\"
              xcopy "C:\src\a\b\c\e.xyz" "B:\dest\a\b\c\e.xyz"
              

              对原始列表中的每个文件重复。在 Win7 上测试。

              【讨论】:

                【解决方案15】:

                要做到这一点拖放使用winzip 有一个目录结构保留选项。只需在目录级别创建一个新的 .zip,将其作为您的根目录并将文件拖入。

                【讨论】:

                • 谢谢,但我一直在寻找可从脚本(批处理)文件中使用的解决方案。所以,没有拖放...
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-07-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-10-18
                相关资源
                最近更新 更多