复制特定文件类型保持文件夹结构

166 cp

我有一个文件夹结构,其中有一堆散布在文件夹中的 *.csv 文件。现在我想将所有 *.csv 文件复制到另一个保持文件夹结构的目的地。

它的工作原理是:

cp --parents *.csv /target
cp --parents */*.csv" /target
cp --parents */*/*.csv /target
cp --parents */*/*/*.csv /target
...
Run Code Online (Sandbox Code Playgroud)

等等,但我想使用一个命令来完成。

msb*_*msb 182

find有一个非常方便的-exec选项:

find . -name '*.csv' -exec cp --parents \{\} /target \;
Run Code Online (Sandbox Code Playgroud)

  • 可能是因为这个 \{\} \; (82认同)
  • `'{}'` 也能正常工作 (15认同)
  • 你能解释为什么大括号必须在这里转义吗? (7认同)
  • 尽管 `-execdir` 比 `-exec` 更安全,简单地将一个替换为另一个并不能按预期保留文件夹结构。 (3认同)
  • 当我尝试使用您的命令复制它们时,为什么会收到消息“正在省略目录”? (3认同)
  • @Noumenon find 的[帮助页面](https://ss64.com/bash/find.html) 说:“-exec command ;执行命令;如果返回 0 状态则为 true。所有以下 find 参数均被视为命令的参数,直到遇到由“;”组成的参数。字符串“{}”将被当前文件名替换,该文件名出现在命令的参数中,而不仅仅是出现在单独的参数中,如在 find 的某些版本中。这两种结构可能都需要转义(使用 '\'`)或引用以保护它们免受 shell 的扩展。” (2认同)
  • 在 Mac 上的终端中使用 find 时,无法识别 --parents 选项。我正在按照 @iain 的答案使用 cpio 。 (2认同)
  • 这个答案拯救了我的一天! (2认同)

Dub*_*ubu 73

您也可以rsync为此使用。

$ rsync -a --prune-empty-dirs --include '*/' --include '*.csv' --exclude '*' source/ target/
Run Code Online (Sandbox Code Playgroud)

如果要保留源树中的空目录,请跳过该--prune-empty-dirs选项:

$ rsync -a --include '*/' --include '*.csv' --exclude '*' source/ target/
Run Code Online (Sandbox Code Playgroud)

如果你希望符号链接,修改日期,文件权限,业主等保存完好,请更换-a与另一组合-rlptgoD。;-)

  • `-m` 是 `--prune-emty-dirs` 的快捷方式。 (2认同)

小智 46

您可以在传递模式下使用findcpio

find . -name '*.csv' | cpio -pdm  /target
Run Code Online (Sandbox Code Playgroud)

这将在当前目录和下面找到所有 .csv 文件并将它们复制到 /target 维护根目录结构.

如果你使用

find /path/to/files -name '*.csv' | cpio -pdm /target
Run Code Online (Sandbox Code Playgroud)

它会找到里面/path/to/files和下面的所有文件,并将它们复制到/target/path/to/files下面。

  • 我从上到下尝试了所有答案,这是唯一一个在第一次尝试中有效的答案 (4认同)
  • 这应该是公认的答案。 (2认同)

Kyl*_*and 34

cp命令允许多个源参数:

cp **/*.csv --parents ../target
Run Code Online (Sandbox Code Playgroud)

警告:我在这里使用递归全局;这是globstarBash 4+ 和 中的选项ksh,并且在zsh. 递归 glob匹配隐藏文件和文件夹,一些实现遵循符号链接,而另一些则不

如果您的 shell 不支持递归全局变量,或者您不想使用它们,您可以执行以下操作:

  • *.csv */*.csv */*/*.csv */*/*/*.csv -- 这当然是非常多余的,需要知道你的目录结构有多深。
  • $(find . -name '*.csv')-- 这匹配隐藏的文件和文件夹。find还支持指定是否遵循符号链接,这可能很有用。

  • “--父母”就是我正在寻找的。谢谢 (3认同)

mar*_*rko 25

这个对我有用:

find -name "*.csv" | xargs cp --parents -t /target

如果您的文件名带有空格,请添加选项-print0-0评论之一中的建议:

find -name "*.csv" -print0 | xargs -0 cp --parents -t /target

  • 最简单语法的最佳答案。工作得很好,很容易记住。在很多情况下`find [东西] | xargs [do stuff]` 非常强大。 (2认同)
  • 如果文件名中有空格,则中断 (2认同)
  • @MichelePiccolini 文件名中的空格可以用`find -print0` 和`xargs -0` 处理。 (2认同)

Ger*_*mia 11

Fromrsync的联机帮助页:

-R, --相对

使用相对路径。这意味着在命令行上指定的完整路径名被发送到服务器,而不仅仅是文件名的最后部分。当您想同时发送多个不同的目录时,这尤其有用。例如,如果您使用此命令:

rsync -av /foo/bar/baz.c remote:/tmp/
Run Code Online (Sandbox Code Playgroud)

...这将在远程机器上的 /tmp/ 中创建一个名为 baz.c 的文件。如果你使用

rsync -avR /foo/bar/baz.c remote:/tmp/
Run Code Online (Sandbox Code Playgroud)

然后将在远程机器上创建一个名为 /tmp/foo/bar/baz.c 的文件,并保留其完整路径。这些额外的路径元素称为“隐含目录”(即上例中的“foo”和“foo/bar”目录)。

所以,这也行:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
Run Code Online (Sandbox Code Playgroud)


Mad*_*ter 8

假设您要从./sourceto复制此结构./destination

cd source
find . -name "*.csv" | xargs tar cvf - | (cd ../destination ; tar xfp -)
Run Code Online (Sandbox Code Playgroud)

我准备把它算作一行,cd source作为一个内置的 shell。