如何复制目录结构但仅包含某些文件

发布于 12-06 08:29 字数 713 浏览 2 评论 0原文

我在 Windows 中找到了问题的解决方案,但我使用的是 Ubuntu:如何使用 Windows 批处理文件复制目录结构但仅包含某些文件?

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

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 的解决方案吗?

I found a solution for my question in Windows but I'm using Ubuntu: How to copy a directory structure but only include certain files using Windows batch files?

As the title says, how can I recursively copy a directory structure but only include some files? For example, given the following directory structure:

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

The files data.zip and info.txt can appear everywhere in the directory structure. How can I copy the full directory structure, but only include files named data.zip and info.txt (all other files should be ignored)?

The resulting directory structure should look like this:

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

Could you tell me a solution for Ubuntu?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

耀眼的星火2024-12-13 08:29:32
$ rsync --recursive --include="data.zip" --include="*.txt" --filter="-! */" dir_1 copy_of_dir_1

要排除 dir3,无论它在树中的位置如何(即使它包含与 --include 匹配的文件):

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

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

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

仅当 dir3 位于 dir2 中时排除它,但无论 dir3 位于何处 dir2 is:

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

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

要仅指定要包含的文件和目录,请运行两个 rsync,一个用于文件,另一个用于目录。在单个 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 不允许使用 指定否定匹配! 运算符。

$ rsync --recursive --include="data.zip" --include="*.txt" --filter="-! */" dir_1 copy_of_dir_1

To exclude dir3 regardless of where it is in the tree (even if it contains files that would match the --includes):

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

To exclude dir3 only at at specific location in the tree, specify an absolute path, starting from your source dir:

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

To exclude dir3 only when it's in dir2, but regardless of where dir2 is:

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

Wildcards can also be used in the path elements where * means a directory with any name and ** means multiple nested directories.

To specify only files and dirs to include, run two rsyncs, one for the files and one for the dirs. The problem with getting it done in a single rsync is that when you don't include a dir, rsync won't enter the dir and so won't discover any files in that branch that may be matching your include filter. So, you start by copying the files you want while not creating any dirs that would be empty. Then copy any dirs that you want.

$ 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

You can combine these if you don't mind that your specified dirs don't get copied if they're empty:

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

The --filter="-! */" is necessary because rsync includes all files and folders that match none of the filters (imagine it as an invisible --include filter at the end of the list of filters). rsync checks each item to be copied against the list of filters and includes or excludes the item depending on the first match it finds. If there's no match, it hits that invisible --include and goes on to include the item. We wanted to change this default to --exclude, so we added an exclude filter (the - in -! */), then we negate the match (!) and match all dirs (*/). Since this is a negated match, the result is that we allow rsync to enter all the directories (which, as I mentioned earlier, allows rsync to find the files we want).

We use --filter instead of --exclude for the final filter because --exclude does not allow specifying negated matches with the ! operator.

单调的奢华2024-12-13 08:29:32

我没有漂亮的衬里,但由于没有其他人回答,您始终可以:

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

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

(当然,请确保您首先位于原始文件夹中!:))

I don't have a beautiful one liner, but since nobody else has answered you can always:

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

For each specific file after copying the directories.

(Make sure you're in the original folder first, of course! :) )

各自安好2024-12-13 08:29:32

这是使用 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/

Here is a one-liner using rsync:

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

If you already have a file list, and want a more scalable solution

 cat file.list | xargs -i rsync -a -f"+ {}" -f'-! */' folder1/ copy_of_folder1/
西瑶2024-12-13 08:29:32
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
cp -pr folder1 copy_of_folder1; find copy_of_folder1 -type f ! \( -name data.zip -o -name info.txt \)  -exec rm -f {} \;
  • first time : copy entirely folder1 to copy_of_folder1
  • second time : erase all files differents from data.zip and
    info.txt
  • At the end, you have your complete structure with only the file data.zip and info.txt
垂暮老矣2024-12-13 08:29:32

tar 在这个领域是一个非常有用的工具。下面我告诉它c创建一个v文件到stdout (-),获取文件列表从 find 在子 shell ($( ... )) 中运行,然后将该流通过管道传输到 tar 中,再次要求它 ex将文件拖到目标目录(-C 〜/目的地)。

假设目标目录为空。如果不是,那么您只会更新与查找匹配的文件,与 ~/destination 相比,~/source 中缺少的文件不会被删除。

要使用它,请从源目录开始:

bob@home:~$ cd source
bob@home:~/source$ tar cvf - $( find -name "info.txt" -o -name "data.zip" ) | tar x -C ~/destination

这是 ~/source 的内容:

bob@home:~/source$ find
.
./file-i-dont-want
./info.txt
./data.zip
./folder1
./folder1/folder2
./folder1/folder2/another-trashy-file
./folder1/folder2/data.zip
./folder1/info.txt

请注意,find 中的 -o 开关表示 或。

这是操作后目的地的内容:

bob@home:~/destination$ find
.
./info.txt
./data.zip
./folder1
./folder1/folder2
./folder1/folder2/data.zip
./folder1/info.txt

tar is a surprisingly useful tool in this space. Below I tell it to create verbosely a file to stdout (-), taking the file list from find running in a subshell ($( ... )), then pipe that stream into tar again asking it to extract the file to the destination directory (-C ~/destination).

It is assumed that the destination directory is empty. If it's not then you'll just get the files matched by the find updated, no files that are absent from ~/source compared to ~/destination will be removed.

To use this, start in the source directory:

bob@home:~$ cd source
bob@home:~/source$ tar cvf - $( find -name "info.txt" -o -name "data.zip" ) | tar x -C ~/destination

Here's the contents of ~/source:

bob@home:~/source$ find
.
./file-i-dont-want
./info.txt
./data.zip
./folder1
./folder1/folder2
./folder1/folder2/another-trashy-file
./folder1/folder2/data.zip
./folder1/info.txt

Note that the -o switch in find means or.

And here's the contents of the destination after the operation:

bob@home:~/destination$ find
.
./info.txt
./data.zip
./folder1
./folder1/folder2
./folder1/folder2/data.zip
./folder1/info.txt
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文