Linux で同じファイルシステム上の 2 つのディレクトリをマージする最適な方法は何ですか?

Linux で同じファイルシステム上の 2 つのディレクトリをマージする最適な方法は何ですか?

結合する必要があるディレクトリが 2 つあります。これら 2 つのディレクトリ内のファイルはすべて大きなファイルです (>= 500 MB)。

アーカイブしたい内容: ソース ディレクトリ内のファイルの場合: 宛先ディレクトリに存在しない場合は、mv宛先ディレクトリに移動します (基本的に新しいハード リンクを作成し、ソース ファイルのリンクを解除するため、高速です)。宛先ディレクトリに存在する場合は、そこにソース ファイルをコピーし、ソース ファイルを削除します。

Linux システムでディレクトリをマージする最も一般的な方法は、オプションrsyncを使用することです--remove-source-files。ただし、宛先ファイルが存在しない場合でもコピー操作が行われるため、これは遅くなります。

もっと良いアイデアはありますか? ありがとうございます。

答え1

基本的に、あなたが説明したのは、存在する場合は上書き先にファイルを移動するということです。つまり、単に移動するだけです。

答え2

失敗するケースがありますmv。以下にサンプルデータを示します。

mkdir -p src/d dest/d
touch src/d/f1 dest/d/f2

失敗例を見るmv:

$ mv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -f src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi src/* dest/
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi -t dest/ src/*      
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty

スクリプト ファイルを作成します。

vim supermove

この例ではエラー チェックは行われず (免責事項: 私の環境では動作しますが、動作をテストしてください... echobeforeを使用するなどmv)、同じパスのファイルを上書きします。また、\;非常に非効率的な find を使用しますが、 prepended を+使用すると正しく動作しません"$dest"。古いバージョンではパスが付加されていないディレクトリが作成され、新しいバージョンの find では次のように表示されます。

find: In '-exec ... {} +' the '{}' must appear by itself, but you specified 'dest/{}'

ただし、xargs を使用すると、おそらくこれを修正する方法が見つかるでしょう。(移動していた 64k のファイル 8TB では数分かかりました)。次のコンテンツを追加します。

#!/bin/bash

src=$1
dest=$2

src=$(readlink -f "$src")
dest=$(readlink -f "$dest")

cd "$src"

# also copy hidden files
shopt -s dotglob

# make dirs (missing old permission,acl,xattr data), and then mv the files
time find * -type d -exec mkdir -p "$dest"/{} \;
time find * -type f -exec mv {} "$dest"/{} \;

# also copy permissions, acls, xattrs
rsync -aAX "$src"/ "$dest"/

そしてそれを実行可能にします:

chmod +rx supermove

そして実行する

./supermove src/ dest/

そして結果は…前:

$ find src dest
src/
src/d
src/d/f1
dest/
dest/d
dest/d/f2

後:

$ find src dest
src
src/d
dest
dest/d
dest/d/f1
dest/d/f2

今はsrc/空のディレクトリだけになっているはずです。その場合はrm -r srcクリーンアップできます。

答え3

mvオプションはすべて競合解決に関するものです。

一つを選ぶ:

-f  force (always overwrite)
-i  interactive (ask whether to overwrite)
-n  no clobber (no overwrite)

これも良いですね:

-v  verbose

そうしないと、データが失われたり、何が起こったのか正確にわからなくなったりする可能性があります。

mv は、ディレクトリの inode を更新するだけなので、同じファイルシステム上でも優れています。ファイルは変更されません。もう 1 つの点は、操作が大きくなると、ソフト エラーなどの問題が発生する可能性が高くなることです。

関連情報