web-dev-qa-db-ja.com

mvが宛先に同じ名前のディレクトリが存在することを処理できないのはなぜですか?

mvは、同じ名前のディレクトリがある宛先にディレクトリを移動できません:

$ mv fortran/ imperative_PLs/
mv: cannot move ‘fortran/’ to ‘imperative_PLs/fortran’: Directory not empty
  1. この場合、mvが機能しないのはなぜですか?システムコールmvinvokeからそれを説明できますか? (できるrsyncと比較)

  2. この場合、mvが機能しないように設計されているのはなぜですか?根拠またはポイントは何ですか?

8
Tim
  1. mvは、そのように設計されていないため、この場合は機能しません。システムコールは(おそらく)どちらかです

    • 同じファイルシステムに移動:rename(元々はlinkおよびunlink
    • ファイルシステム間を移動:再帰的なファイルコピーの後に再帰的なunlink
  2. 意見:このユースケースを処理するように設計されていなかったため、動作するように設計されたnotであるとはあまり考えていません。 1つのことをうまく実行することを目的とした「シンプルな」ツールの場合は、これらのアクションパスのどれをmvに取るかを示すスイッチのセットを提供する必要があります。

    • 現在の実装のように、エラーで保釈する
    • マージするには、ファイルがすでに存在する場合にエラーでベイルします
    • マージするには、既存のターゲットファイルを置き換えます

マージ/置換アクションが必要な場合は、cpの後にrmを付けるか、ファイルツリーコピーユーティリティtarのいずれかを使用して、簡単に実装できます。 paxなど.

6
roaima

mvrsyncは類似したプログラムではありません。特に、mvは、単にオブジェクトの名前を変更しようとすることがよくあります。同じファイルシステムにある場合、コンテンツはまったくコピーされません。

まだ持っていない場合imperative_PLs/fortran、次にmvは、既存のfortranディレクトリを取得して、ツリー内のそのポイントに名前を変更します。

しかし、その場所にはすでに(コンテンツを含む)ディレクトリがあります。名前は単一のオブジェクトしか参照できないため、既存のディレクトリを削除するか名前を変更する必要があります。 mvは、どちらも実行したくないと想定して中止します。

rsyncは代わりに、個々のファイルと他のコンテンツをfortran内にコピーし、それらを既存のimperative_PLs/fortranディレクトリ。

代わりにrenameと考えると、動作がわかりやすくなる場合があります。

10
BowlOfRed

mvは、実際にはrenameの下にあります。

ファイルを別のファイルに移動すると、mvはユーザーが何をしているのかを知っていると見なし、宛先ファイルを上書きします。

ディレクトリを別のディレクトリに移動する場合、mvは、元のディレクトリのベース名を保持し、それをターゲットディレクトリに作成することを想定しています。宛先側にその名前のディレクトリがまだない場合、またはその名前のディレクトリが存在するが空の場合、操作は成功します。

ただし、ターゲットディレクトリが既に存在し、空でない場合、これはrenameではなくなりますが、これは再帰的なファイルとディレクトリの削除であるはずです。 renameはそれを実行するように設計されていないため、失敗します。mvは、それを実行したくないと想定して失敗したため、それ以上は進みません。

7
jlliagre

ファイルシステム間を移動するときのエラーメッセージは、少し冗長です。

_# mv a/foo b/bar
mv: inter-device move failed: 'a/foo' to 'b/bar/foo'; unable to remove target: Directory not empty
_

ですから、あなたが期待しているようにディレクトリをマージしようとしているのではなく、ソースの名前を変更する前にターゲットを削除しています。ディレクトリの削除は、空の場合にのみ機能します。

Syscallsに関しては、同じファイルシステム内では、rename()のみです。

_rename("a/foo", "a/bar/foo")            = -1 ENOTEMPTY (Directory not empty)
_

ファイルシステム間を移動するとき、最初にrename()がこのケースを検出し、rmdir()で簡単に試みます。

_rename("a/foo", "b/bar/foo")            = -1 EXDEV (Invalid cross-device link)
rmdir("b/bar/foo")                      = -1 ENOTEMPTY (Directory not empty)
_

mvはもっと努力することができますが、したくありません。 ;)

3
frostschutz