2008-08-26 125 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的目錄。

相關問題