bash目录树中的递归复制文件

bash目录树中的递归复制文件,bash,tree,copy,Bash,Tree,Copy,My application X将项目组织在具有特定树的文件夹中。树的第一级是定义的(硬约束),而所有内容都是自由组织的 我的目标是迭代项目树的所有文件夹,根据条件解析文件夹名称以获得目标,然后将选定的目标复制到新的项目文件夹中,保持树结构,以便应用程序X不会抱怨 到目前为止,我已经想到了这个: cp -pr `find . -type d | grep -i targetstring` ../newProjectFolder/ 这有问题:1)它不保留文件夹树;2) 引发许多错误cp:无法统计

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

我的目标是迭代项目树的所有文件夹,根据条件解析文件夹名称以获得目标,然后将选定的目标复制到新的项目文件夹中,保持树结构,以便应用程序X不会抱怨

到目前为止,我已经想到了这个:

cp -pr `find . -type d | grep -i targetstring` ../newProjectFolder/
这有问题:1)它不保留文件夹树;2) 引发许多错误
cp:无法统计
(另请参阅)。它不仅仅是按预期的那样工作

此外,还需要解析
find
的输出

正如建议的那样,我能够克服父母的第一个问题。然而,由于第2点的原因,我复制的方式比我需要的少,所以毕竟不是一个解决方案

我正在寻找一种解决这个问题的简单方法。基于脚本的解决方案可用编辑:由于该链接被标记为与提供的链接重复,我将重新措辞:我想要一个解决方案,不需要显式执行,否则我将无法执行。管道
find
grep
提供了所有要复制的位置,但是
cp
正在抱怨。我们如何将它们提供给
cp
,而不让它抱怨

我正在使用suggersted的
-exec
寻找一些东西,并得出了以下结论,这是不起作用的(不会复制任何内容)(只复制部分树结构,并且该结构中的文件只有在与正则表达式匹配时才被复制):

“一行”但
sed
不适用于文件名中的换行符
$'\n'

find . -iname "*targetstring*" | grep -o ^\./[^/]*
find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'
eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder
mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;
假设您将
cd
放入项目文件夹并运行
find.
始终使用

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

find . -iname "*targetstring*" | grep -o ^\./[^/]*
find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'
eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder
mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;
示例树
searchProjectFolder/some/parent/folders/matched/targetstring/foo/bar/

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

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

创建新项目文件夹并在示例树上运行“查找”

mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*"
示例树上的结果是

./some/parent/folders/matched/targetstring
./some
"./some"
cp -a "./some" ../newProjectFolder
cp -a --parents "./some/parent/folders/matched/targetstring" ../newProjectFolder
现在
find
结果通过管道传输到
grep
,因此我们只能将字符串剪切到第一级

find . -iname "*targetstring*" | grep -o ^\./[^/]*
find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'
eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder
mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;
示例树上的结果是

./some/parent/folders/matched/targetstring
./some
"./some"
cp -a "./some" ../newProjectFolder
cp -a --parents "./some/parent/folders/matched/targetstring" ../newProjectFolder
代替
grep
我们可以使用
sed
引用“文件夹名称”(可能有空格)

find . -iname "*targetstring*" | grep -o ^\./[^/]*
find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'
eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder
mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;
示例树上的结果是

./some/parent/folders/matched/targetstring
./some
"./some"
cp -a "./some" ../newProjectFolder
cp -a --parents "./some/parent/folders/matched/targetstring" ../newProjectFolder
最后,让我们看一下
cp
所有带有
eval
的文件夹,因为“文件夹名称”都被引用了。这是“一行”:

find . -iname "*targetstring*" | grep -o ^\./[^/]*
find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'
eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder
mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;
示例树上的结果是

./some/parent/folders/matched/targetstring
./some
"./some"
cp -a "./some" ../newProjectFolder
cp -a --parents "./some/parent/folders/matched/targetstring" ../newProjectFolder
为了更好地理解,我将解释sed

sed -n 's,^\(\./[^/]*\).*,"\1",p'
sed -n 's, ^  \(  \.  /  [^/]*  \)  .* , "\1" ,p'
-n
=不打印输入
p in
,p'
=仅打印匹配的输出

\1
=打印第一个捕获组
\(
=捕获组的开始
\)
=捕获组结束

^
=仅匹配字符串的开头
\.
=单点(

/
=单斜杠(路径分隔符)
[^/]
=任何单个字节,但不是斜杠
[^/]*
=任何不包含斜杠的字符串
=单字节
*
=任何字符串

因此,(第一个)捕获组是(行的开头)
/示例字符串

捕获组被引用(
“\1”

“/示例字符串”


编辑:

如果您只想复制文件夹
targetstring/
(带父目录树)

find . -iname "*targetstring*" | grep -o ^\./[^/]*
find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p'
eval cp -a $(find . -iname "*targetstring*" | sed -n 's,^\(\./[^/]*\).*,"\1",p') ../newProjectFolder
mkdir newProjectFolder
cd searchProjectFolder
find . -iname "*targetstring*" -exec cp -a --parents {} ../newProjectFolder \;
示例树上的结果是

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

副本:。我正在寻找一种解决这个问题的简单方法。删除换行符和boom,这是一个单行耶,好吧,所有东西都是这样的一行,甚至是一个脚本,我在循环上使用嵌套循环。有没有一种方法可以在不循环的情况下实现这一点?如果我采用我的方法,称之为简单的、专门设计的软件部件?我不知道。试试你想复制哪个文件夹
/some/parent/folders/matched/targetstring/foo/bar/
查找-iname“*targetstring*”-exec cp-a--parents{}../newProjectFolder\只复制文件夹“targetstring”(带树)-我想你想复制整个文件夹“some”?我真的很喜欢这个!这一次,它没有带if条件的while循环,而是按照预期使用软件。我只想复制
targetstring/
及其所有内容,将树的根保持在
some/
。假设有些人还有一个文件夹
parent2/
,并且
parent2/
的子项都不匹配,则不应复制
parent2/
。冲洗并在所有级别重复。然后您自己已经有了解决方案,只需将
-regex
替换为
-iname
(请参阅我最后的评论)