Unix Shell文件复制拼合文件夹结构

时间:2020-03-05 18:43:12  来源:igfitidea点击:

在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

解决方案

回答

在bash中:

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

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

回答

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

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

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

(-0允许它在文件名中包含奇怪字符(如空格)时起作用。)

不幸的是,我认为Mac带有BSD风格的工具。有人知道等效于" -t"开关的"标准"吗?

回答

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

回答

如果我们真的只想运行一个命令,为什么不运行一个命令并运行它呢?像这样:

$ 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选项相比,需要记住的语法更少。

回答

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

我确实认为文件会被覆盖,所以想出了一种不同的方法。用名称中的层次结构替换路径中的每个/,并将所有文件放在一个平面文件夹中。

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

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

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