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


15

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

cp最小のファイルが最初にコピーされるように、ファイルサイズの順にコピー操作を実行する必要があることを伝える方法はありますか?


1
XYの問題が関係していないことを確認するために、これを行う理由を説明できますか?
goldilocks 14

4
@ TAFKA'goldilocks '-ビデオファイルがたくさんあるので、各ディレクトリの品質をテストしたいと思います。最小のビデオは、残りのファイルが同様に悪いかどうかを迅速に示してくれます。
nbubis

回答:


10

これにより、ジョブ全体が一度に実行されます。すべての子ディレクトリで、すべてファイル名の問題なく単一のストリームで実行されます。持っているすべてのファイルを最小から最大にコピーします。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

または、Gillesはディレクトリのアクセス許可を保持するために彼の答えで非常に良いポイントを示しているので、私も試してみるべきです。これでうまくいくと思います:

find . -type d -printf '[ -d "'"${DESTINATION}"'/%p" ] || 
    cp "%p" -t "'"${DESTINATION}"'"\n' |
. /dev/stdin

mkdirとにかくそれが速くなることに賭けたいと思います。


1
くそー +1
goldilocks 14

3
@ TAFKA'goldilocks 'これはお世辞になります。どうもありがとう。
mikeserv 14

15

ここに使用する迅速で汚い方法があります rsyncです。この例では、10 MB未満のものはすべて「小さい」と考えています。

最初に小さなファイルのみを転送します。

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  doesnt
          affect  the  data  that  goes  into  the file-lists, and thus it
          doesnt 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つのコピーを取得し、ソフトリンクはそれぞれの2つのコピーの実際のファイルに変換されます。あなたはとのより良い多くを行うだろう--copy-dest=DIRと/または--compare-dest=DIR私は思います。リンクが見つからなかったため、自分の回答を投稿--hard-dereferenceしたtar後に自分を追加しなければならなかった原因しかわかりません。rsyncとにかく、実際には他のユーザーとのローカルファイルシステムにより固有の動作をしていると思います。以前はUSBキーで使用していたため、帯域幅の制限を設定しない限り、バスがあふれます。代わりに他のいずれかを使用すべきだったと思います。
mikeserv 14

1
「迅速で汚れた方法」の場合は+1。少なくとも自動化の目的と将来の保守性のために、通常はシンプルな方が優れています。これは実際にはかなりきれいだと思います。「エレガント」と「クラッディ」および「ロバスト」と「不安定」は、設計目標として競合する場合がありますが、バランスを取ることができます。これはエレガントかなり堅牢だと思います。
ワイルドカード

4

ないcp直接、それは十分にその能力を超えています。ただしcp、正しい順序でファイルを呼び出すように手配できます。

Zshでは、glob修飾子を使用して、サイズでファイルを簡単にソートできます。以下は、サイズの昇順でファイル/path/to/source-directoryをunder からunder にコピーする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 **/*(/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

2

cp -rこれを直接行う方法はないと思います。ウィザード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番目の引数(リテラル以外の任意のもの0)を追加すると、コピーする代わりに、ファイルのサイズがバイト単位で追加された状態で、レポートの出力が標準出力に出力されます。

    4523 /src/path/file.x -> /dest/path/file.x
    12124 /src/path/file.z -> /dest/path/file.z

    これらはサイズの昇順であることに注意してください。

  • cp34行目のコマンドはリテラルシェルコマンドであるため、スイッチを使用-aして任意の操作を実行できます(すべての特性を保持するために使用しました)。

  • File::FindそしてFile::Basename、両方のコアモジュールです彼らはperlののすべてのインストールで使用できますすなわち。


おそらく、これが唯一の正解です。それとも...タイトル-ちょうど変更された...?私のブラウザウィンドウは呼び出されますがcp - copy smallest files first?、投稿のタイトルはcopy smallest files first?とにかく、オプションは決して傷つけることはありませんが、それでも、あなたとデビッドが使用した唯一のものでcpあり、あなただけがそれを引き出しました。
mikeserv 14

@mikeserv私が使用しcpた唯一の理由は、それが(クロスプラットフォーム指向の)perlで* nixファイルの特性を保持する最も簡単な方法だからです。ブラウザバーに表示される理由cp - は、選択したタグの中で最も人気のあるタグが実際のタイトルの前に表示される(IMO間抜けな)SE機能のためです。
goldilocks 14

OK、それから私は賛辞を撤回します。本当にそうではありませんがpearl、この辺りの木工から出てくるのを見ることはあまりありません。
mikeserv 14

1

別のオプションは、duからの出力でcpを使用することです。

oldIFS=$IFS
IFS=''
for i in $(du -sk *mpg | sort -n | cut -f 2)
do
    cp $i destination
done
IFS=$oldIFS

これはまだ1行で行うことができますが、あなたが読むことができるように私はそれを分割します


少なくとも$ IFSについて何かする必要はありませんか?
mikeserv 14

はい...私は誰もそのファイル名に改行を持っていないと仮定しておく
デビッド・ウィルキンス

1
また、これは、OPが説明したディレクトリ階層の再帰を処理していないようです。
cpugeniusmv 14

1
@cpugeniusmv正しい...私は何らかの形で再帰部分を逃しました....再帰を処理するためにこれを変更できましたが、この時点で他の答えがより良い仕事をすると思います。質問を見た人に役立つように、ここに残しておきます。
デビッドウィルキンス14

1
@DavidWilkins-これは非常に役立ちます。
nbubis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.