[英]How to copy a directory structure but only include certain files
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? 我在Windows中找到了我的问题的解决方案,但我正在使用Ubuntu: 如何复制目录结构但只包含使用Windows批处理文件的某些文件?
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. 文件data.zip和info.txt可以出现在目录结构的任何地方。 How can I copy the full directory structure, but only include files named
data.zip
and info.txt
(all other files should be ignored)? 如何复制完整的目录结构,但只包含名为
data.zip
和info.txt
文件(应忽略所有其他文件)?
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? 你能告诉我Ubuntu的解决方案吗?
$ 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 --include
s): 要排除
dir3
无论它在树中的哪个位置(即使它包含与--include
s匹配的--include
):
--exclude 'dir3/' (before `--filter`)
To exclude dir3
only at at specific location in the tree, specify an absolute path, starting from your source dir: 要仅在树中的特定位置排除
dir3
,请从源目录开始指定绝对路径:
--exclude '/dir1/dir2/dir3/' (before `--filter`)
To exclude dir3
only when it's in dir2
, but regardless of where dir2
is: 要仅在
dir2
排除dir3
,而不管dir2
在哪里:
--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 rsync
s, one for the files and one for the dirs. 要仅指定要包含的文件和目录,请运行两个
rsync
,一个用于文件,另一个用于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. 在单个
rsync
完成它的问题是,当您不包含目录时, rsync
将不会进入目录,因此不会发现该分支中可能与您的包含过滤器匹配的任何文件。 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). 该
--filter="-! */"
是必要的,因为rsync的包括所有文件和匹配没有过滤条件的文件夹(把它想象成一种无形的--include
在过滤器列表的末尾过滤器)。 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. rsync
根据筛选器列表检查要复制的每个项目,并根据找到的第一个匹配项包含或排除该项目。 If there's no match, it hits that invisible --include
and goes on to include the item. 如果没有匹配,它击中无形
--include
并继续列入的项目。 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 ( */
). 我们想将此默认值更改为
--exclude
,因此我们添加了一个排除过滤器( -
in -! */
),然后我们否定匹配( !
)并匹配所有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). 由于这是一个否定的匹配,结果是我们允许
rsync
进入所有目录(正如我之前提到的,它允许rsync
找到我们想要的文件)。
We use --filter
instead of --exclude
for the final filter because --exclude
does not allow specifying negated matches with the !
我们使用
--filter
而不是--exclude
作为最终过滤器,因为--exclude
不允许使用!
指定否定匹配!
operator. 运营商。
Here is a one-liner using rsync: 这是使用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/
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! :) ) (当然,请确保您首先在原始文件夹中!:))
cp -pr folder1 copy_of_folder1; find copy_of_folder1 -type f ! \( -name data.zip -o -name info.txt \) -exec rm -f {} \;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.