サイズに基づいてファイルを再帰的に移動して構造を維持する方法

サイズに基づいてファイルを再帰的に移動して構造を維持する方法

各ファイルがサブフォルダに配置されている 1 つのディレクトリ ツリーから、「300 MB」を超えるファイルを移動したい

例: ディレクトリ構造は次のようになります:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

予想される結果は、各ファイルがサブフォルダーに移動されるディレクトリ ツリーの「移動」です。

dirB/            #  normal directory
dirB/file1       #  moved from dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  moved from dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  moved from dirA/y/file3

しかしfind /path/ -type f -size +300m、その後はどうなりますか? 残念ながら、一部のファイルには、キーボードで見つけられるあらゆる種類の文字が含まれています。

私はこれを見てきました誰かが話しているのですcpioが、私はそのプログラムを知りません...

PS: GNU Parallel をインストールしておけば、処理速度が上がるかもしれません。

答え1

簡単な方法は翻訳. 使用することができますglob 修飾子種類やサイズなどの基準に従ってファイルを照合します。ワイルドカードパターン **/任意のレベルのサブディレクトリに一致します。履歴修飾子 hおよび は、tディレクトリとファイル名のベース部分を抽出する簡単な方法です。mkdir -p必要に応じて を呼び出してディレクトリを作成します。

cd dirA
for x in **/*(.Lm+300); do
  mkdir -p ../dirB/$x:h &&
    mv -- $x ../dirB/$x
done

移植可能な方法は を使用することですfind。 を使用して-exec、ファイルごとにシェル スニペットを呼び出します。

cd dirA
find . -type f -size +300000k -exec sh -c 'for x do
  mkdir -p "../dirB/${x%/*}"
  mv "$x" "../dirB/$x"
done' sh {} +

並列化は入出力にはほとんど役に立ちません。並列化により複数の CPU を活用できますが、CPU が I/O のボトルネックになることはほとんどありません。

答え2

Perlは当然の選択です。 、、renameとしてインストールできます。renrenamepren

find dirA -type f -size +300M | ren 's:^dirA/:dirB/:'

ただし、ファイルが別のマウント ポイントに移動されている場合は機能せず、ディレクトリが存在しない場合は失敗します。

GNU Parallel は遅くなります:

cd dirA
find . -type f -size +300M | parallel mkdir -p ../dirB/{//}
find . -type f -size +300M | parallel mv {} ../dirB/{}

ただし、ファイルを別のファイル システムに移動するためにコピーしてから削除するルーチンを実行する必要がある場合でも機能します。

答え3

要するに:

find dirA -type f -size +300m -printf "mv %p dirB/%P\n" | sh

ただし、開始する前に dirB 内のすべてのサブディレクトリが存在している必要があります。このため、次の 2 つの手順を実行することをお勧めします。

cd dirA
find . -type f -size +300m -printf "mkdir -p ../dirB/%h\nmv %p ../dirB/%P\n" | sh

cpio に関して (実際にはサブディレクトリの問題を解決します):

(cd dirA; find . -type f -size +300m) | cpio -p -md  dirB

(あなたが言及している同じスレッドのcp(1)に関しては、それはあなたにとって良くありません。なぜなら、それはコピーするからです。 全て ファイル そして dirBの下にdirAというサブディレクトリを作成します。フラグ-Tこの問題を解決できます)

答え4

これで十分でしょう。

find /path -type f -size +300m | while read A ; do DEST=${A/dirA/dirB} ; echo mkdir -p $(dirname $DEST) 2>/dev/null; echo mv $A $DEST ; done

まずそのまま実行して健全性をチェックし、提案されたコマンドに問題がなければ、要素なしで再実行しますecho

ファイル構造の例では、次のコマンドが生成されます

mkdir -p ./dirB
mv ./dirA/file1 ./dirB/file1
mkdir -p ./dirB/x
mv ./dirA/x/file2 ./dirB/x/file2
mkdir -p ./dirB/y
mv ./dirA/y/file3 ./dirB/y/file3

関連情報