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


52

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

例:ディレクトリ構造があります:

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

回答:


50

Linux(より正確にはGNUと、カーネルとしてLinuxを備えたシステムで一般的に見られるbusybox実装をcp使用)および最近のFreeBSDでは、次のようになります。

cp -al dirA dirB

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


paxFreeBSDののように、cp -aシンボリックリンクをハードリンクしないことに注意してください。
ステファンシャゼル

ハードリンクは、個別のファイルシステムのマウント間では機能しないことに注意してください。
デイブ

24

POSIXlyでは、次pax-lオプションを使用して読み取り+書き込みモードで使用します。

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

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

今では、標準ではありますが、そのコマンドは必ずしも非常にポータブルではありません。

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

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

  • バグのため、と組み合わせてpax使用-rwlすると、Solaris 10は(少なくとも)動作しません-s。何らかの理由で、元のパスとコピーされたパスの両方に置換を適用するようです。そのため、上記では、link("dirB/file", "dirB/file")代わりにいくつかの処理を試みlink("dirA/file", "dirB/file")ます。
  • FreeBSDでは、symlinkpaxタイプのファイルのハードリンクを作成しません(POSIXで許可されている動作)。それだけでなく、置換をシンボリックリンクのターゲットに適用します(POSIXでは許可されていない動作です)。だから、例えばあるかどうシンボリックリンクはで、それはなりますの中で。foo -> AAdirAfoo -> BAdirB

また、あなたは同じですが、その内容に格納された任意のファイルパスを行いたい場合$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改行文字で終わる場合は失敗します)。

今では、GNU / Linuxシステムでは何も役に立ちませんpax

paxPOSIXがtarand cpioコマンドの機能をマージするために作成したことに注意してください。

cpioある歴史的 POSIX発明とは対照的に(1977から)Unixコマンド、およびGNUの実装では、ウェル(ないように存在するpaxもの)。そのため、それはもはや標準コマンドではありませんが(SUSv2にありました)、それでも非常に一般的であり、通常依存できる機能のコアセットがあります。

と同等のものはにpax -rwlなりますcpio -pl。しかしながら:

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

だからcpio

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

-s / A / B /は私の例に固有のもののようです。ソースディレクトリ名とターゲットディレクトリ名が変数$ sourcedirと$ targetdirである場合、これをどのように行いますか?
グドマン

@GudmundurOrn、編集を参照してください。
ステファンシャゼル

OS Xでこのコマンドを実行すると、「pax:ファイル./a.txtをそれ自体にリンクできません」というエラーメッセージが表示されます。ソースディレクトリを実際の名前に置き換え、/ A / Bと最後のドットをそのままにして、コマンドを文字通り使用しました。私は何かを誤解していますか?
デシベル

@Db、-s /A/B置き換えABそうdirAなりましたdirB。ソースディレクトリ名にnoがある場合、Aそれはそれ自体をコピー(リンク)します。おそらくより良いアプローチについては、残りの回答も参照してください。
ステファンシャゼル


2

ファイルのスナップショットまたはバックアップ(すべてまたは一部)を作成するためのハードリンクコピー機能を探している場合は、を参照してくださいrsnapshot


1
それは面白い。しかし、ハードリンクは、ファイルが変更されない場合の優れたスナップショットメカニズムにすぎないと思います。右?
グドマンドゥルオーン

@Gudmundur Orn; これは正しいです。私の答えで述べたツールは、ファイルが一意になるように新しいスナップショットを作成します。つまり、既存の(変更されていない)ファイルはハードリンクとして作成され、新しいファイル(または既存のファイルの変更されたバージョン)は新しいファイルとして作成されます。したがって、結果として冗長性が最も低くなります。
ジャニス

0

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

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

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