最小のファイルを最初にコピーしますか?

最小のファイルを最初にコピーしますか?

再帰的にコピーするサブディレクトリと、ファイルを含む大きなディレクトリがあります。

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インストールで使用できます。

関連情報