Unix shell文件复制flattening文件夹结构

时间:2008-08-26 09:22:35

标签: unix shell

在UNIX bash shell(特别是Mac OS X Leopard)上,将具有特定扩展名的每个文件从文件夹层次结构(包括子目录)复制到同一目标文件夹(没有子文件夹)的最简单方法是什么?

显然存在源层次结构中存在重复的问题。如果他们被覆盖,我不介意。

示例:我需要复制以下层次结构中的每个.txt文件

/foo/a.txt
/foo/x.jpg
/foo/bar/a.txt
/foo/bar/c.jpg
/foo/bar/b.txt

到名为'dest'的文件夹并获取:

/dest/a.txt
/dest/b.txt

5 个答案:

答案 0 :(得分:52)

在bash中:

find /foo -iname '*.txt' -exec cp \{\} /dest/ \;

find会在路径/foo下找到与通配符*.txt匹配的所有文件,不区分大小写(这就是-iname的含义)。对于每个文件,find将执行cp {} /dest/,找到的文件代替{}

答案 1 :(得分:13)

Magnus解决方案的唯一问题是它为每个文件分配了一个新的“cp”进程,这个进程并不是非常有效,尤其是在存在大量文件的情况下。

在Linux(或其他具有GNU coreutils的系统)上,您可以执行以下操作:

find . -name "*.xml" -print0 | xargs -0 echo cp -t a

(当文件名中有奇怪的字符 - 如空格时,-0允许它工作。)

不幸的是,我认为Macs配备了BSD风格的工具。有人知道“标准”等同于“-t”开关吗?

答案 2 :(得分:11)

上面的答案不允许名称冲突,因为提问者不介意文件被覆盖。

我会介意文件被覆盖,所以提出了一种不同的方法。用 - 替换路径中的每个/ - 将层次结构保存在名称中,并将所有文件放在一个平面文件夹中。

我们使用find来获取所有文件的列表,然后使用awk创建一个带有原始文件名的mv命令,然后将修改后的文件名传递给bash以便执行。

find ./from -type f | awk '{ str=$0; sub(/\.\//, "", str); gsub(/\//, "-", str); print "mv " $0 " ./to/" str }' | bash

其中./from和./to是mv from和to的目录。

答案 3 :(得分:3)

如果你真的只想运行一个命令,那为什么不把它拿出去运行呢?像这样:

$ find /foo  -name '*.txt' | xargs echo | sed -e 's/^/cp /' -e 's|$| /dest|' | bash -sx

但是除非你这么做或者拥有大量的文件,否则这在性能上并不重要。但是要注意名称串通。我在测试中注意到GNU cp至少警告了碰撞:

cp: will not overwrite just-created `/dest/tubguide.tex' with `./texmf/tex/plain/tugboat/tubguide.tex'

我认为最干净的是:

$ find /foo  -name '*.txt' | xargs -i cp {} /dest

要记住的语法少于-exec选项。

答案 4 :(得分:1)

就FreeBSD盒子上的cp手册页而言,不需要-t开关。如果传递两个以上的名称,cp将假定命令行上的最后一个参数为目标目录。