【问题标题】:How to copy a directory structure but only include certain files如何复制目录结构但仅包含某些文件
【发布时间】:2011-09-26 04:53:23
【问题描述】:

我在 Windows 中找到了我的问题的解决方案,但我使用的是 Ubuntu:How to copy a directory structure but only include certain files using Windows batch files?

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

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

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

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

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

你能告诉我一个 Ubuntu 的解决方案吗?

【问题讨论】:

标签: bash shell ubuntu


【解决方案1】:
$ rsync --recursive --include="data.zip" --include="*.txt" --filter="-! */" dir_1 copy_of_dir_1

排除dir3,无论它在树中的什么位置(即使它包含与--includes 匹配的文件):

--exclude 'dir3/' (before `--filter`)

要仅在树中的特定位置排除 dir3,请指定从源目录开始的绝对路径:

--exclude '/dir1/dir2/dir3/' (before `--filter`)

仅在 dir2 中排除 dir3,但无论 dir2 在哪里:

--exclude 'dir2/dir3/' (before `--filter`)

通配符也可用于路径元素,其中* 表示具有任意名称的目录,** 表示多个嵌套目录。

要仅指定要包含的文件和目录,请运行两个rsyncs,一个用于文件,一个用于目录。在单个 rsync 中完成它的问题是,当您不包含目录时,rsync 不会进入该目录,因此不会发现该分支中可能与您的包含过滤器匹配的任何文件.因此,您首先要复制所需的文件,而不是创建任何空的目录。然后复制任何你想要的目录。

$ rsync --recursive --prune-empty-dirs --include="*.txt" --filter="-! */" dir_1 copy_of_dir_1
$ rsync --recursive --include '/dir1/dir2/' --include '/dir3/dir4/' --filter="-! */" dir_1 copy_of_dir_1

如果您不介意指定的目录为空时不会被复制,您可以将它们组合起来:

$ rsync --recursive --prune-empty-dirs --include="*.txt" --include '/dir1/dir2/' --include '/dir3/dir4/' --filter="-! */" dir_1 copy_of_dir_1

--filter="-! */" 是必需的,因为 rsync 包括所有与过滤器都不匹配的文件和文件夹(将其想象为过滤器列表末尾的不可见 --include 过滤器)。 rsync 根据过滤器列表检查要复制的每个项目,并根据找到的第一个匹配项包含或排除该项目。如果没有匹配,它会点击那个不可见的--include 并继续包含该项目。我们想将此默认值更改为--exclude,因此我们添加了一个排除过滤器(-! */ 中的-),然后我们否定匹配(!)并匹配所有目录(*/)。由于这是一个否定匹配,结果是我们允许rsync 进入所有目录(正如我之前提到的,这允许rsync 找到我们想要的文件)。

我们使用--filter 而不是--exclude 作为最终过滤器,因为--exclude 不允许使用! 运算符指定否定匹配。

【讨论】:

  • 感谢 Roger Dahl,一切正常。但是,需要一个可扩展的解决方案。与现实世界一样,我们不能在排除标志中包含这么多文件夹名称。要包含的文件应按照上面的 Windows 解决方案进行参数化。如何仅包含所需的目录和文件并排除所有其他文件夹和文件,同时保留文件夹结构。其次,请让我知道为什么这里需要过滤规则,因为我们正在包含和排除所需的文件。
【解决方案2】:

我没有一个漂亮的班轮,但由于没有其他人回答你总是可以:

find . -name 'file_name.extension' -print | cpio -pavd /path/to/receiving/folder

复制目录后的每个特定文件。

(当然,首先要确保您在原始文件夹中!:))

【讨论】:

  • 嗨,这并不能解决问题,因为需要手动复制所有内容
  • @ayniam:“手动复制所有内容”是什么意思?使用cpio的全部意义在于让机器进行复制。
【解决方案3】:

这是一个使用 rsync 的单行代码:

 rsync -a -f"+ info.txt" -f"+ data.zip" -f'-! */' folder1/ copy_of_folder1/

如果您已经有一个文件列表,并且想要一个更具可扩展性的解决方案

 cat file.list | xargs -i rsync -a -f"+ {}" -f'-! */' folder1/ copy_of_folder1/

【讨论】:

    【解决方案4】:
    cp -pr folder1 copy_of_folder1; find copy_of_folder1 -type f ! \( -name data.zip -o -name info.txt \)  -exec rm -f {} \;
    
    • 第一次:将 folder1 完全复制到 copy_of_folder1
    • 第二次:擦除所有与 data.zip 不同的文件和 info.txt
    • 最后,您有了完整的结构,只有文件 data.zip 和 info.txt

    【讨论】:

    • 嗨,Michel,这是不可扩展的,因为我们需要复制 70 GB 的数据并再次擦除其中的大部分。感谢您的回答
    • 嗨 ayniam,你是对的,70 GB 对于这种程序来说有点太多了。但我不明白为什么即使目录为空,Chan Than 也需要完整的结构。祝你有美好的一天。
    猜你喜欢
    • 2010-10-03
    • 1970-01-01
    • 2015-08-28
    • 2011-01-30
    • 1970-01-01
    • 2013-04-25
    • 2016-05-07
    • 2017-09-13
    • 1970-01-01
    相关资源
    最近更新 更多