mvとcp&rmは違うのか。
背景
以前、短い実行時間で合計数GBの複数ファイルを移動することを求められた。その際に、mvコマンドを使えばファイルポインタ書き換えるだけだし、一瞬じゃない?と思ったけど、それは本当か?実はcp&rmをやっているだけかも?と思い、調査した結果を記載する。
mvコマンドについて
ドキュメントを参照すると以下のような記載がある。
mvコマンド
mv - ファイルを移動する(ファイル名を変更する)
ちなみにcpは以下
cp - ファイルやディレクトリをコピーする
わからん...
と思いながら調べていると以下の記事が。
めっちゃしっかり書いてくれてた。
ここをちゃんと読めば書いてありますが、まとめます。
mv ≠ cp&rmなのか
結論から言うと、基本的にはそうだが、場合によってはcp&rmになる、が正しい。
簡単に説明すると。mvの中身は
- システムコールのrename() が呼ばれる。
- rename() が成功すれば終了→ファイル名が変わったり、ファイルが移動できたりする。
- rename() 失敗ならば、cp&rmを行う。
ちなみにrename()は以下を参照
rename()が失敗するときは?
上記にエラーの条件の記載がある。
よくあることとして、
EBUSY
oldpath または newpath がディレクトリで、何らかのプロセスが使用中 (多分、カレントワーキングディレクトリか、ルートディレクトリか、 読み込みのためにオープンされているかでろう) もしくは、システムが使用中 (例えばマウントポイントである) であり、システムがこれをエラーであると判断したために rename が失敗した。 (このような場合に EBUSY を返すことは規格では要求されていない点に注意すること。 このような場合に、rename をとにかく実行してみるのは何の問題もない。 ただし、そのような状況で、システムが他に返すエラーがない場合には EBUSY を返すことが許されている。)
要するに
- ファイルが何かのシステムで開かれている。
- rename先のファイルがシンボリックリンクやハードリンクされている先にある。
と理解した。
また、
EXDEV
oldpath と newpath が同じマウントされたファイルシステムに存在しない。 (Linux は 1 つのファイルシステムを複数のマウント位置に マウントすることを許可している。 しかし rename() は、たとえ同じファイルシステムであっても、 別々のマウント位置を跨いでは動作しない。)
などもある。これは、
上記の通り、同じファイルシステムにないファイルは、rename()が失敗する。
mvができないときは、上記のような要因を疑ってみるといいかもしれない。
結論
mvコマンドはファイルポインタを変更する、という動作が基本だが、場合によってはcp&rmになる。
以上です。
Discussion