bash保留目录树中的递归复制文件 [英] Recursive copy files in bash preserving dir tree

查看:94
本文介绍了bash保留目录树中的递归复制文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序X将项目组织在具有特定树的文件夹中。树的第一级被定义(硬约束),而所有内容都是自由组织的。

My application X organizes projects in folders with a specific tree. The first level of the tree is defined (hard constraint), while all the contents are freely organized.

我的目标是遍历项目树的所有文件夹,进行解析文件夹名称以根据条件获取目标,然后将选定的目标复制到新的项目文件夹中,并保留树结构,以使应用程序X不会抱怨。

My goal is to iterate over all folders of the project tree, parse folder names to get targets based on conditions, then copy the selected targets to a new project folder, keeping the tree structure, so that application X is not going to complain.

到目前为止,我已经提出了这个建议:

So far, I've come up with this:

cp -pr `find . -type d | grep -i targetstring` ../newProjectFolder/

这有问题:1)它不保留文件夹树; 2)引发很多错误 cp:无法统计(另请参见 时,无法在unix中统计错误,我会得到此错误)。

This has issues: 1) it doesn't preserve folder tree; 2) throws a lot of errors cp: cannot stat (see also this). It isn't just working as intended.

此外,解析 find 的输出是通常是个坏主意

我能够用<$ c克服第一个问题$ c>-父母,如建议在此处。但是,由于第2点,我的复制方式少于我需要的方式,因此毕竟不是解决方案。

I was able to overcome first problem with --parents as suggested here. However, I'm copying way less than what I need due to point 2, so not a solution after all.

我正在寻找一个该问题的一线解决方案 。您可以在此处获得基于脚本的解决方案。 编辑:,因为这被标记为所提供的链接的重复,所以我要重新措辞:我想要一个不需要在不需花时间的情况下明确解决的方法。通过管道查找 grep 提供要复制的所有位置,但是 cp 正在抱怨。我们如何在不抱怨的情况下将它们喂入 cp

I am looking for a one-liner solution to the problem. Script based solution is available here. as this was marked as duplicated of the link provided, I'll rephrase a little: I want a solution where I don't need to explicitly while and if-else my way to it. Piping find and grep provides all the locations to be copied, but cp is complaining. How do we feed them to cp, without it complaining?

我在寻找使用<$ c $的东西c> -exec 如建议的那样此处,并提出以下内容,该方法不起作用(什么都不会被复制)(仅复制部分树结构,并且仅在与regex匹配的情况下复制该结构中的文件,例如很好):

I was looking for something using -exec as suggersted here, and came up with the following, which is not working (nothing gets copied) (only partial tree structure is copied, and files inside that structure are only copied if they match the regex as well):

find . -regex ".*targetstring.*" -exec cp -rp --parents \{\} ../newProjectFolder \;


推荐答案

单线但 sed 不适用于文件名 $'\n'的换行符

"one-liner" but sed will not work for newlines $'\n' in filename

假设您 cd 进入项目文件夹并运行 find。始终与

它将匹配 targetstring (在任何级别上),并从第一级别复制整个(包含)树>

assuming you cd into project folder and run find . always with .
it will match targetstring (on any level) and will copy the whole (containing) tree from first level

示例树

searchProjectFolder / some / parent / folders / matched / targetstring / foo / bar /

在<$ c $中搜索 * targetstring * c> searchProjectFolder / 将复制整个 ./ some 文件夹(包括所有文件和子文件夹)

a search for *targetstring* inside searchProjectFolder/ will copy whole ./some folder (including all files and subfolders)

-regex -ipath 将打印所有文件, -iname 仅会打印匹配的文件夹 targetstring / 本身。您可以使用 -mindepth 5 -maxdepth 5 将搜索限制到特定级别,并指定目标类型只能将文件夹型d 匹配(但让我们暂时取消此选项)

while -regex or -ipath will print all files, -iname will only print the matching folder targetstring/ itself. you can limit search to specific level(s) with -mindepth 5 and -maxdepth 5, and specify the target type to match folders only with -type d (but let us take away this options for now)

创建newProjectFolder并在示例树上运行查找

mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*"

示例树的结果是

./some/parent/folders/matched/targetstring

现在查找结果通过管道传输到 grep ,因此我们可以将字符串剪切到第一级仅

now find result is piped to grep so we can cut the string to first level only

find . -iname "*targetstring*" | grep -o ^\./[^/]*

示例树的结果是

./some

代替 grep ,我们可以使用 sed 引用文件夹名称(可能有空格) )

instead of grep we can use sed to quote the "folder name" (may have spaces)

find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'

示例树上的结果是

"./some"

最后让我们 cp 所有<$ c的文件夹$ c> eval 因为引用了文件夹名称。这是单线:

finally let's cp all folders with eval because "folder names" are quoted. this is the "one-liner":

eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder

示例树的结果是

cp -a "./some" ../newProjectFolder

为了更好的理解,我将解释sed

sed -n 's,^\(\./[^/]*\).*,"\1",p'
sed -n 's, ^  \(  \.  /  [^/]*  \)  .* , "\1" ,p'

-n =不打印输入
,p'中的
p =仅打印匹配的输出

-n = do not print input
p in ,p' = print only matching output

\ 1 =打印第一个捕获组

\( =开始捕获组

\) =捕获组结束

\1 = print the first capture group
\( = begin of capture group
\) = end of capture group

^ =仅匹配字符串的开头

\。 =单点(

/ =单斜杠(路径分隔符)

[^ /] =任何单个字节,但不是斜杠

[^ /] * =任何不包含斜杠的字符串

=单字节

。* =任何字符串

^ = match begin of string only
\. = single dot (.)
/ = single slash (path delimiter)
[^/] = any single byte, but not a slash
[^/]* = any string not containing slashes
. = single byte
.* = any string

因此(第一个)捕获组是(行首)

。/example字符串

so the (first) capture group is (begin of line)
./example string

捕获组被引用( \1

。/示例字符串

编辑:

如果只想复制文件夹 targetstring /

another "real" one-liner if you only want to copy folder targetstring/ (with parent tree)

mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;

示例树的结果为

cp -a --parents "./some/parent/folders/matched/targetstring" ../newProjectFolder

这篇关于bash保留目录树中的递归复制文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆