2008-08-26 127 views
34

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

很明显,在源层次结构中存在重复的问题。我不介意他们是否被覆盖。

例子:我需要每一个.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 

回答

51

在bash:

​​

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

+3

-exec cp -t dest/{} +会更快,因为它只需运行一次cp,具有多个参数。 -t是--target-directory的缩写。 -l在这里可能很有用,可以制作硬链接。代替。也许-u,结束每个文件名的最新版本,而不是第一个找到。 – 2009-12-05 21:00:21

+0

这里的一般bash问题... {}是专门用于查找还是代表管道价值的一种方法? – 2014-03-04 18:43:06

+0

@BrianBolton`{```特定于`find` – 2014-03-04 21:51:03

13

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

在Linux(或其他系统与GNU的coreutils),你可以这样做:

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

(-0允许它当你的文件名有奇怪的字符工作 - 如空格 - 在其中)

不幸的是我认为Macs带有BSD风格的工具。任何人都知道与“-t”开关等效的“标准”?

1

只要在FreeBSD盒上的cp手册页去,就不需要-t开关。如果传递了两个以上的名字,cp将假定命令行上的最后一个参数是目标目录。

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选项记住。

10

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

我不介意文件被覆盖,所以想出了一个不同的方法。使用以下命令替换路径中的每个/:保留名称中的层次结构,并将所有文件放在一个平面文件夹中。

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

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

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

相关问题