Find
如何即時復製文件列表並調整目標文件名?
當我不需要調整目標文件名時,我可以這樣做:
$ find -type f -name '*.pat' -print0 | xargs -O cp -t /path/to/dest
這是安全的,因為文件名甚至可能包含換行符。
替代:
$ find -type f -name '*.pat' -print0 | cpio -p -0 -d /path/to/dest
現在我的問題是目標是 VFAT 文件系統……因此文件名中不允許使用某些字元(例如“?”)。這意味著我必須調整目標文件名。
就像是
for i `find -type f -name '*.pat'` ; do cp "$i" `echo $i | sed 's/?/_/'` done
僅適用於沒有空格的文件名 - 我可以將 IFS 更改為換行符 - 但是如何將 ‘\0’ 設置為 IFS?
而且 - for 循環會導致與文件一樣多的 forks/exec(mv/sed) - 這比開始的兩個範例所需的少數 forks/exec 多得多。
解決該問題的替代方法是什麼?
pax
至少可以在 Debian、Suse、OpenBSD、NetBSD 上找到:find . -type f -name '*.pat' -print0 | pax -0rws'/?/_/gp' /path/to/dest/
pax
是一個標準實用程序(與tar
or相反cpio
),但它的-0
選項不是,儘管可以在一些實現中找到。如果同時存在 a
?.pat
和_.pat
文件,它們最終將被替換為相同的名稱,因此其中一個將覆蓋目標中的另一個。同樣,如果有一個_
and?
目錄,它們的內容將合併到_
目標目錄中。使用 GNU
sort
和 GNUuniq
,您可以預先檢查衝突:find . -type f -name '*.pat' -print0 | tr '?' _ | sort -z | uniq -zd | tr '\0' '\n'
這將報告衝突的文件(但不是目錄)。
您可以使用
zsh
’szmv
來解決衝突,但這仍然意味著每個文件一個mkdir
和一個:cp
autoload zmv mkdir-and-cp() {mkdir -p -- $3:h && cp $@} zmv -n -Qp mkdir-and-cp '(**/)*.pat(D.)' '/path/to/dest/$f:gs/?/_/'
-n
(高興時刪除)。