mv
は、同じ名前のディレクトリがある宛先にディレクトリを移動できません:
$ mv fortran/ imperative_PLs/
mv: cannot move ‘fortran/’ to ‘imperative_PLs/fortran’: Directory not empty
この場合、mv
が機能しないのはなぜですか?システムコールmv
invokeからそれを説明できますか? (できるrsync
と比較)
この場合、mv
が機能しないように設計されているのはなぜですか?根拠またはポイントは何ですか?
mv
は、そのように設計されていないため、この場合は機能しません。システムコールは(おそらく)どちらかです
rename
(元々はlink
およびunlink
)unlink
意見:このユースケースを処理するように設計されていなかったため、動作するように設計されたnotであるとはあまり考えていません。 1つのことをうまく実行することを目的とした「シンプルな」ツールの場合は、これらのアクションパスのどれをmv
に取るかを示すスイッチのセットを提供する必要があります。
マージ/置換アクションが必要な場合は、cp
の後にrm
を付けるか、ファイルツリーコピーユーティリティtar
のいずれかを使用して、簡単に実装できます。 pax
など.
mv
とrsync
は類似したプログラムではありません。特に、mv
は、単にオブジェクトの名前を変更しようとすることがよくあります。同じファイルシステムにある場合、コンテンツはまったくコピーされません。
まだ持っていない場合imperative_PLs/fortran
、次にmv
は、既存のfortran
ディレクトリを取得して、ツリー内のそのポイントに名前を変更します。
しかし、その場所にはすでに(コンテンツを含む)ディレクトリがあります。名前は単一のオブジェクトしか参照できないため、既存のディレクトリを削除するか名前を変更する必要があります。 mv
は、どちらも実行したくないと想定して中止します。
rsync
は代わりに、個々のファイルと他のコンテンツをfortran
内にコピーし、それらを既存のimperative_PLs/fortran
ディレクトリ。
代わりにrename
と考えると、動作がわかりやすくなる場合があります。
mv
は、実際にはrename
の下にあります。
ファイルを別のファイルに移動すると、mv
はユーザーが何をしているのかを知っていると見なし、宛先ファイルを上書きします。
ディレクトリを別のディレクトリに移動する場合、mv
は、元のディレクトリのベース名を保持し、それをターゲットディレクトリに作成することを想定しています。宛先側にその名前のディレクトリがまだない場合、またはその名前のディレクトリが存在するが空の場合、操作は成功します。
ただし、ターゲットディレクトリが既に存在し、空でない場合、これはrename
ではなくなりますが、これは再帰的なファイルとディレクトリの削除であるはずです。 rename
はそれを実行するように設計されていないため、失敗します。mv
は、それを実行したくないと想定して失敗したため、それ以上は進みません。
ファイルシステム間を移動するときのエラーメッセージは、少し冗長です。
_# 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
はもっと努力することができますが、したくありません。 ;)