再帰的にコピーするサブディレクトリと、ファイルを含む大きなディレクトリがあります。
cp
最小のファイルが最初にコピーされるようにファイルサイズ順にコピー操作を実行する必要があることを知らせる方法はありますか?
答え1
次はrsync
。
まず、小さなファイルのみを転送してください。
rsync -a --max-size=10m srcdir dstdir
その後、残りのファイルを転送します。以前に送信された小さなファイルは、変更しない限り再コピーされません。
rsync -a srcdir dstdir
~からman 1 rsync
--max-size=SIZE
This tells rsync to avoid transferring any file that is larger
than the specified SIZE. The SIZE value can be suffixed with a
string to indicate a size multiplier, and may be a fractional
value (e.g. "--max-size=1.5m").
This option is a transfer rule, not an exclude, so it doesn’t
affect the data that goes into the file-lists, and thus it
doesn’t affect deletions. It just limits the files that the
receiver requests to be transferred.
The suffixes are as follows: "K" (or "KiB") is a kibibyte
(1024), "M" (or "MiB") is a mebibyte (1024*1024), and "G" (or
"GiB") is a gibibyte (1024*1024*1024). If you want the multi‐
plier to be 1000 instead of 1024, use "KB", "MB", or "GB".
(Note: lower-case is also accepted for all values.) Finally, if
the suffix ends in either "+1" or "-1", the value will be offset
by one byte in the indicated direction.
Examples: --max-size=1.5mb-1 is 1499999 bytes, and
--max-size=2g+1 is 2147483649 bytes.
もちろん、ファイルごとの転送順序が最も小さいものから最大のものの順に厳密に決まったわけではありませんが、これがおそらくあなたの要件に適合する最も簡単な解決策であると思います。
答え2
今回は、ファイル名の問題なしに、すべてのサブディレクトリから単一ストリームで完全な操作が完了しました。最小ファイルから最大ファイルまですべてのファイルをコピーします。mkdir ${DESTINATION}
まだ存在しない場合は、これを行う必要があります。
find . ! -type d -print0 |
du -b0 --files0-from=/dev/stdin |
sort -zk1,1n |
sed -zn 's/^[^0-9]*[0-9]*[^.]*//p' |
tar --hard-dereference --null -T /dev/stdin -cf - |
tar -C"${DESTINATION}" --same-order -xvf -
しかし、それは知っていますか?これがしないのは空サブディレクトリ。そのパイプに対していくつかのリダイレクトを実行できますが、これは発生を待つ競合状態にすぎません。最も単純なものが最善かもしれません。それでは、次のようにします。
find . -type d -printf 'mkdir -p "'"${DESTINATION}"'/%p"\n' |
. /dev/stdin
あるいは、Gilesがディレクトリ権限の保存に対する答えに良い点を指摘したので、私もそうする必要があります。私はこれがトリックを実行すると思います。
find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] ||
cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin
とにかくそれより速いと確信していますmkdir
。
答え3
直接的ではありませんが、cp
それはその能力をはるかに超えています。ただし、cp
正しい順序でファイルを呼び出すようにソートできます。
Zshを使用すると、ファイルをサイズ別に簡単に並べ替えることができます。グローバル予選。以下は、サイズが大きくなる順序で/path/to/source-directory
ファイルを下から下にコピーするzshフラグメントです/path/to/destination-directory
。
cd /path/to/source-directory
for x in **/*(.oL); do
mkdir -p /path/to/destination-directory/$x:h &&
cp -- $x /path/to/destination-directory/$x:h
done
あなたはそれを使用することができますzcp
機能。ただし、まずターゲットディレクトリを作成する必要があります。これは不思議なオネライナーで行うことができます。
autoload -U zmv; alias zcp='zmv -C'
cd /path/to/source-directory
mkdir -p **/*(/e\''REPLY=/path/to/destination-directory/$REPLY'\')
zcp -Q '**/*(.oL)' '/path/to/destination-directory/$f'
これはソースディレクトリの所有権を維持しません。これを行うには、cpio
などの適切なコピープログラムを使用する必要がありますpax
。これにより、追加またはcp
呼び出しを行う必要がなくなります。zcp
cd /path/to/source-directory
print -rN -- **/*(^.) **/*(.oL) | cpio -0 -p /path/to/destination-directory
答え4
cp -r
直接できる方法はないようです。魔法 /solution を得るfind
までには無限の時間がかかることがあるので、awk
クイックPerlスクリプトは次のようになります。
#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);
use File::Find;
use File::Basename;
die "No (valid) source directory path given.\n"
if (!$ARGV[0] || !-d -r "/$ARGV[0]");
die "No (valid) destination directory path given.\n"
if (!$ARGV[1] || !-d -w "/$ARGV[1]");
my $len = length($ARGV[0]);
my @files;
find (
sub {
my $fpath = $File::Find::name;
return if !-r -f $fpath;
push @files, [
substr($fpath, $len),
(stat($fpath))[7],
]
}, $ARGV[0]
);
foreach (sort { $a->[1] <=> $b->[1] } @files) {
if ($ARGV[2]) {
print "$_->[1] $ARGV[0]/$_->[0] -> $ARGV[1]/$_->[0]\n";
} else {
my $dest = "$ARGV[1]/$_->[0]";
my $dir = dirname($dest);
mkdir $dir if !-e $dir;
`cp -a "$ARGV[0]/$_->[0]" $dest`;
}
}
これを使用してください:
./whatever.pl /src/path /dest/path
パラメーターはすべて次のようにする必要があります。絶対パス;
~
または、シェルが絶対パスに拡張する他のすべての操作を実行します。3番目の引数(textを除く
0
)を追加するとコピーされませんが、ファイルサイズ(バイト単位)が前に追加され、実行するアクションのレポートがstdoutとして印刷されます。4523 /src/path/file.x -> /dest/path/file.x 12124 /src/path/file.z -> /dest/path/file.z
サイズが昇順に並んでいますので参考にしてください。
34行目のコマンドはリテラルシェルコマンドなので、スイッチを使用して必要な操作をすべて実行できます(すべての機能を維持する
cp
ために使用しただけです)。-a
File::Find
コアモジュールですFile::Basename
。つまり、すべてのPerlインストールで使用できます。