web-dev-qa-db-ja.com

各ファイルのハードリンクを使用してディレクトリを再帰的にコピーする方法

各ファイルが元のファイルへのハードリンクであるディレクトリツリーの「コピー」を作成したい

例:私はディレクトリ構造を持っています:

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

期待される結果、各ファイルが元のファイルへのハードリンクであるディレクトリツリーの「コピー」は次のとおりです。

dirB/            #  normal directory
dirB/file1       #  hardlink to dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  hardlink to dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  hardlink to dirA/y/file3
56
Gudmundur Orn

Linux(より正確には、GNUとbusyboxcpの実装で、Linuxをカーネルとして持つシステムで通常見られる)と最近のFreeBSDでは、これはどうやって:

cp -al dirA dirB

よりポータブルなソリューションについては、StéphaneChazelasによるpaxとcpioを使用した回答を参照してください

54
Gudmundur Orn

POSIXlyの場合、paxを読み取りと書き込みモードで-lオプションを指定して使用します。

pax -rwlpe -s /A/B/ dirA .

-peは、GNU cp-aのように)コピーされるファイル(この場合はディレクトリのみ)のすべての可能な属性を保持します。

標準ですが、そのコマンドは必ずしもportableとは限りません。

まず、多くのGNU/Linuxベースのシステムには、デフォルトでpaxが含まれていません(これはオプションのPOSIXユーティリティではありません)。

次に、いくつかのバグといくつかの実装の不適合により、そのコードで多くの問題が発生します。

  • バグのため、Solaris 10 pax(少なくとも)は、-rwl-sを組み合わせて使用​​すると機能しません。何らかの理由で、元のパスとコピーされたパスの両方に置換が適用されているようです。したがって、上記ではlink("dirB/file", "dirB/file")の代わりにlink("dirA/file", "dirB/file")を実行しようとします。
  • freeBSDでは、paxはタイプsymlinkのファイルのハードリンクを作成しません(POSIXで許可されている動作)。それだけでなく、置換をシンボリックリンクのターゲットにも適用します(動作not POSIXで許可されています)。たとえば、dirAfoo -> AAシンボリックリンクがある場合、それはdirBfoo -> BAになります。

また、同じことをしたいが、$src$dstにコンテンツが格納されている任意のファイルパスを使用する場合は、pax -rwl -- "$src" "$dst"$src内に$dstの完全なディレクトリ構造を作成することを理解することが重要です(存在する必要があり、ディレクトリである必要があります)。たとえば、$srcfoo/barの場合、$dst/foo/barが作成されます。

代わりに、$dst$srcのコピーにしたい場合は、おそらく次のようにするのが最も簡単です。

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")

(これはまた、上記の問題のほとんどを回避しますが、$dstの絶対パスが改行文字で終わる場合は失敗します)。

これは、paxがないGNU/Linuxシステムでは役に立ちません。

興味深いのは、paxtarコマンドとcpioコマンドの機能をマージするためにPOSIXによって作成されたことです。

cpioは、POSIXの発明とは対照的にhistorical Unixコマンド(1977年から)であり、GNUの実装もあります(pax one)。したがって、もはやstandardコマンドではありませんが(SUSv2にありました)、それは非常に一般的であり、通常は信頼できるコア機能のセットがありますオン。

pax -rwlに相当するものはcpio -plです。しかしながら:

  1. cpioは、引数ではなくstdinの入力ファイルのリストを取ります(改行で区切られているため、改行文字を含むファイル名はサポートされていません)。
  2. すべてのファイルを指定する必要があります(通常、findの出力をフィードします(findcpioは同じ人が共同で開発しました))。
  3. メタデータは保持されません(一部のcpio実装には、一部を保持するオプションがありますが、移植性はありません)。

cpioの場合:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")
27

簡潔な答え:

cd $source_folder
pax -rwlpe . $dest_folder
6
lkraider

あなたがそのファイルを探している場合ハードリンクのコピー機能を使用して、ファイルの(すべてまたは一部の)バックアップのスナップショットを作成し、rsnapshotを確認します。

2
Janis

@ gudmundur-ornの答えは正しいですが、LinuxでBtrFSを使用している場合はcp a --reflink=auto dirA dirBでうまくいくはずですが、ファイルが実際に異なり、一方を変更しても他方は変更されません。 APFSを搭載したMacでcp -cを使用すると、ほとんど同じことができます(不可能な場合、autoは完全なコピーを実行し、-cは失敗します)。

どのCOWファイルシステムでもこれを実行できるはずですが、ベンダーは標準のコマンドラインオプションについて合意していません。

0
rbanffy