ターゲットファイル名を調整する必要がない場合は、次のことができます。
$ 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 ループはファイル (mv/sed) と同じくらい多くのフォーク/exec を発生させます。これは、最初の2つの例で必要とされるいくつかのフォーク/execよりもはるかに多いです。
この問題を解決するための代替案は何ですか?
ベストアンサー1
pax
少なくともDebian、Suse、OpenBSD、NetBSDで見つかります。
find . -type f -name '*.pat' -print0 | pax -0rws'/?/_/gp' /path/to/dest/
pax
は標準ユーティリティ(同じtar
または逆cpio
)、-0
いくつかの実装で見つけることができますが、そのオプションはそうではありません。
?.pat
ファイルとファイルの両方が_.pat
存在する場合は、同じ名前に置き換えられるため、ターゲット上の1つが別のファイルを上書きします。同様に_
、ディレクトリがある場合、その内容はターゲットディレクトリ?
にマージされます。_
GNUsort
とGNUを使用すると、uniq
競合を事前に確認できます。
find . -type f -name '*.pat' -print0 |
tr '?' _ |
sort -z |
uniq -zd |
tr '\0' '\n'
競合するファイルを報告します(ディレクトリを除く)。
zsh
'を使用してzmv
競合を解決することはできますが、これはまだファイルごとにmkdir
1プラス1を意味します。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
)。