フォルダー内のすべてのハードリンクを解除する


10

(同じフォルダーまたは別の場所に)ハードリンクが設定された特定の数のファイルを含むフォルダーがあり、これらのファイルのハードリンクを解除したいので、それらのファイルは独立し、内容の変更が影響を与えません他のファイル(リンク数は1になります)。

以下では、基本的に各ハードリンクを別の場所にコピーしてから元の場所に戻すソリューションを示します。

ただし、この方法はかなり粗雑でエラーが発生しやすいので、ファイルのハードリンクを解除するコマンドがあるかどうかを知りたいのですが。

粗野な答え:

ハードリンクのあるファイルを検索します(編集:ハードリンクのあるソケットなども検索するには、を使用しますfind -not -type d -links +1):

find      -type f -links +1 # files only
find -not -type d -links +1 # files, sockets etc.

ファイルをハードリンク解除する別の方法(ファイルを別の場所にコピーして元に戻す): 編集: Celadaが言ったように、タイムスタンプと権限が失われないように、以下のcp -pを実行するのが最善です。 編集: 一時ディレクトリを作成し、その下のファイルにコピーします。一時ファイルを上書きする代わりに、一部のデータを上書きするリスクを最小限に抑えますが、mvコマンドは依然として危険です(@Tobuに感謝)。 編集: 同じファイルシステム(@MikkoRantalainen)に一時ディレクトリを作成してみてください。

# This is unhardlink.sh
set -e
for i in "$@"; do
  temp="$(mktemp -d -- "${i%/*}/hardlnk-XXXXXXXX")"
  [ -e "$temp" ] && cp -ip "$i" "$temp/tempcopy" && mv "$temp/tempcopy" "$i" && rmdir "$temp"
done

だから、非ハードリンクのすべてのハードリンク(の編集:変更-type f-not -type d、上記参照)。

find -not -type d -links +1 -print0 | xargs -0 unhardlink.sh

私はその「粗末な」とは考えません。これを高速化する唯一の方法は、おそらくsendfile()システムコールを使用して、オープンソースファイルのリンクを解除し、ターゲットをインプレースで書き換えることです。率直に言って、努力する価値はない。
マシューイフ

私が使用してこのコマンドを実行したときに「粗製物」とは、私はそれを意味し、例えば、cp -iスイッチを、それがオーバーライドする必要があるかどうかを尋ねる私にいくつかのメッセージを吐いた./fileXXXXXX$temp、TMPFILEは、一意のファイル名を与えるべきであるにも関わらず、ファイルを)そこので必見なんらかの競合状態などになり、データが失われる危険性があります。
スザンヌデュペロン

1
ファイルが存在するのは正常です。tempfileを使用して作成しただけです(nb:mktempの代わりに非推奨になりましたが、それが問題の原因ではありません)。
東武

1
あなたはunhardlink.shニーズがunhardlinkedするというファイルが含まれている同じディレクトリ内に一時ディレクトリを作成する必要があります。そうしないと、一時ディレクトリが現在の作業ディレクトリにあるため、再帰呼び出しが別のファイルシステム内で再帰し、ファイルシステムの境界を越えて移動する可能性があります。"$(dirname "$i")/hardlink-XXXXXX"代わりにmktempの引数として渡すことができると思います。
ミッコランタライネン

1
@MikkoRantalainenありがとう、更新しました!ファイルシステムが何らかのunionfsまたはファイルシステムである場合、fuse実際にはpath/to/hardlink-XXXとは異なる物理ストレージメディアにディスパッチされる可能性がありますが、それpath/to/original-fileについてできることはあまりないことに注意してください。
スザンヌデュペロン

回答:


9

スクリプトに改善の余地があります。たとえば-pcpコマンドにオプションを追加して、非ハードリンク操作全体で権限とタイムスタンプが保持されるようにします。エラーが発生した場合に一時ファイルが削除されるように、エラー処理を追加できます。しかし、あなたの解決策の基本的な考えが機能する唯一のものです。ファイルのハードリンクを解除するには、ファイルをコピーしてから、元の名前の上にコピーを戻す必要があります。「粗雑でない」ソリューションはなく、このソリューションは、別のプロセスが同時にファイルにアクセスしている場合に競合状態になります。


実際、ものをコピーするときは常にcp -aを使用して、すべてを保存し、再帰してシンボリックリンクをシンボリックリンクとしてコピーします。今回はなぜそれを忘れたのかわかりませんが、あなたの答えを見て、すべてのタイムスタンプがおかしくなり、バックアップから(かなり苦痛に)回復しなければならなかったことがわかりました。
スザンヌデュペロン

5

ディスク領域を焼き尽くしたい場合で、比較的新しいバージョンtar(Ubuntu 10.04やCentOS 6のバージョンなど)を使用している--hard-dereference場合は、オプションで遊ぶことができます。

何かのようなもの:

$ cd /path/to/directory
$ ls -l *
bar:
total 12
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 2 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

(私が走っていた場所ln foo/[12] bar

$ tar cvf /tmp/dereferencing.tar --hard-dereference .
$ tar xvf /tmp/dereferencing.tar
$ ls -l *
bar:
total 12
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 1 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

manページから:

   --hard-dereference
          follow hard links; archive and dump the files they refer to

タールにできないことはほとんどないと思います。いい修正。
Joseph Kern、2012年

すべてをコピーするのに十分なディスク容量がなかったということを忘れていました。基本的に、cp -a --no-preserve=links /path/to/folder /path/to/copy && rm -rf /path/to/folder && mv /path/to/copy /path/to/folder私が間違っていなければ、メソッドはと同じです。ただし、tarの方がディスクシークが少なく、スラッシングが少ないため、この方法の方が効率的だと思います。rsyncを使用して同じことを達成できますが、cpメソッドよりもさらに低いパフォーマンスです。
スザンヌデュペロン

1
多くの余分なディスクの使用を避けるために、次のようなものを実行することtar cvf - --hard-dereference . | tar xf -は可能かもしれませんが、物事が爆発する原因となる競合状態があるかもしれません。私はそれを試していません、そして私は今のところそうすることに少し気が進まないです。
-cjc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.