📁

mvとcp&rmは違うのか。

2021/01/16に公開

背景

以前、短い実行時間で合計数GBの複数ファイルを移動することを求められた。その際に、mvコマンドを使えばファイルポインタ書き換えるだけだし、一瞬じゃない?と思ったけど、それは本当か?実はcp&rmをやっているだけかも?と思い、調査した結果を記載する。

mvコマンドについて

ドキュメントを参照すると以下のような記載がある。
mvコマンド

mv - ファイルを移動する(ファイル名を変更する)

https://linuxjm.osdn.jp/html/GNU_fileutils/man1/mv.1.html

ちなみにcpは以下

cp - ファイルやディレクトリをコピーする

https://linuxjm.osdn.jp/html/GNU_fileutils/man1/cp.1.html

わからん...

と思いながら調べていると以下の記事が。

https://qiita.com/junjis0203/items/9e8f642b04d9754f1139

めっちゃしっかり書いてくれてた。
ここをちゃんと読めば書いてありますが、まとめます。

mv ≠ cp&rmなのか

結論から言うと、基本的にはそうだが、場合によってはcp&rmになる、が正しい。

簡単に説明すると。mvの中身は

  • システムコールのrename() が呼ばれる。
  • rename() が成功すれば終了→ファイル名が変わったり、ファイルが移動できたりする。
  • rename() 失敗ならば、cp&rmを行う。

ちなみにrename()は以下を参照
https://linuxjm.osdn.jp/html/LDP_man-pages/man2/rename.2.html

rename()が失敗するときは?

上記にエラーの条件の記載がある。
よくあることとして、

EBUSY
oldpath または newpath がディレクトリで、何らかのプロセスが使用中 (多分、カレントワーキングディレクトリか、ルートディレクトリか、 読み込みのためにオープンされているかでろう) もしくは、システムが使用中 (例えばマウントポイントである) であり、システムがこれをエラーであると判断したために rename が失敗した。 (このような場合に EBUSY を返すことは規格では要求されていない点に注意すること。 このような場合に、rename をとにかく実行してみるのは何の問題もない。 ただし、そのような状況で、システムが他に返すエラーがない場合には EBUSY を返すことが許されている。)

要するに

  • ファイルが何かのシステムで開かれている。
  • rename先のファイルがシンボリックリンクやハードリンクされている先にある。

と理解した。

また、

EXDEV
oldpath と newpath が同じマウントされたファイルシステムに存在しない。 (Linux は 1 つのファイルシステムを複数のマウント位置に マウントすることを許可している。 しかし rename() は、たとえ同じファイルシステムであっても、 別々のマウント位置を跨いでは動作しない。)

などもある。これは、
上記の通り、同じファイルシステムにないファイルは、rename()が失敗する。

mvができないときは、上記のような要因を疑ってみるといいかもしれない。

結論

mvコマンドはファイルポインタを変更する、という動作が基本だが、場合によってはcp&rmになる。

以上です。

https://zenn.dev/soshimiyamoto/articles/cc74aa483fbf7d

Discussion