Macでファイルをコピーするコマンド|cpで上書きを避ける
mac ファイル コピー コマンドで調べて最初に出てくるのはcpですが、この命令には知らずに使うと困る性質が1つあります。コピー先に同じ名前のファイルがあっても、何も聞かずに上書きします。Finderで同じ操作をすれば置き換えるかどうかの確認が出るので、その落差でファイルを失う場面が起きます。この記事では、上書きを避ける書き方、フォルダをまとめて運ぶときの指定、属性を保つか落とすかの違い、そしてcpより向いている道具の選び分けまでを順に整理します。
cpは既定で何も聞かずに上書きする
cpの基本の形は、コピー元とコピー先を並べて書くだけです。
cp before after
afterが存在しないファイル名なら、beforeの複製が新しく作られます。afterがフォルダなら、その中にbeforeと同じ名前で複製が置かれます。そして、afterが既にあるファイルの名前だった場合の挙動が問題になります。
cpコマンドはファイルを複製するコマンド。複製したファイル名を同時に指定することも可能。 ファイルを新しいファイルで上書き afterが存在するファイルの場合、beforeの内容で上書き 出典: qiita.com
確認は出ません。上書きされた側の中身は戻りません。Time Machineやバージョン管理の外にあるファイルなら、その時点の内容は失われます。
これを避けるための指定が3つ用意されています。-iを付けると、上書きになる場面で確認が出ます。yまたはYで始まる答えを返したときだけコピーが進みます。-nを付けると、既にあるファイルは上書きせずに飛ばします。-fを付けると、権限にかかわらず削除して作り直します。
この3つは互いを打ち消す関係にあります。-fは前に書いた-iと-nを無効にし、-iは前に書いた-fと-nを無効にします。つまり同じ行に複数書いた場合、後ろに書いたものの指定が効きます。エイリアスでcpに-iを付けている環境で、意図せず-fが後ろに付く書き方をすると、確認が消えます。
普段から確認を挟みたいなら、シェルの設定にエイリアスを1行書くのが手軽です。
alias cp='cp -i'
ただし、スクリプトの中ではエイリアスは効きません。自動で走る処理では-nを明示して、上書きが起きない形にしておくほうが安全です。
フォルダごと運ぶときは、末尾のスラッシュで結果が変わる
フォルダを対象にするときは-Rを付けます。付けないままフォルダを指定すると、コピーされずに終わります。
cp -R ~/Documents/work ~/Backup
この書き方では、Backupの中にworkというフォルダが作られ、その下に中身が入ります。ここで、コピー元の末尾にスラッシュを付けると結果が変わります。
cp -R ~/Documents/work/ ~/Backup
末尾にスラッシュがあると、フォルダそのものではなく中身が対象になります。Backupの直下にworkの中身が展開されます。1文字の違いで階層が1つずれるため、実行の前にコピー先の中身を一度見ておくと取り違えに気付けます。
-Rにはもう1つ性質があります。途中でエラーが起きても、そこで止まらずに残りのコピーを続けます。大量のファイルを運んだあとで、何件が失敗したのかを画面から読み取るのは簡単ではありません。件数を確かめたい場合は、あとでコピー元とコピー先の数を数えて突き合わせる手順を挟みます。
また、cpはハードリンクを別々のファイルとして複製します。同じ実体を複数の名前で指していた構成は、コピー後には別々の実体に分かれます。この関係を保ったまま運ぶ必要がある場合は、tarやpaxのような、まとめて包む側の道具に任せる形になります。
属性を運ぶか落とすかで、コピーの意味が変わる
ファイルには中身以外にも、更新日時、権限、所有者、そして拡張属性が付いています。cpは既定でこれらの一部を引き継ぎません。コピー先の更新日時は実行した時刻になり、権限は作成時の設定に従います。
元の状態を保ちたいときは-pを付けます。更新日時、アクセス日時、ファイルのフラグ、モード、所有者とグループが保たれ、アクセス制御リストと拡張属性も運ばれます。リソースフォークも拡張属性の側に含まれます。
cp -Rp ~/Documents/work ~/Backup
-aと書くと、-RpPをまとめて指定したことになります。階層をたどり、属性を保ち、シンボリックリンクはたどらずにリンクのまま複製します。バックアップの目的なら、この形が出発点になります。
逆に、属性を落としたい場面もあります。-Xを付けると、拡張属性とリソースフォークを運びません。他のOSとやり取りするファイルや、ダウンロードの印を持ち越したくないファイルでは使い道があります。ただし、アプリのバンドルに対してこれを当てると署名の検証が通らなくなります。macOS向けの配布物を運ぶときは、この指定を外しておく判断になります。
-pと合わせて-Nを書くと、ファイルのフラグだけを運ばない形になります。書き込み禁止のフラグが立ったファイル群を、編集できる状態で複製したい場面で使われます。
Macに固有のメタデータをまとめて扱うなら、dittoのほうが素直です。リソースフォークとHFSのメタデータの保持が既定の動作で、macOS 10.5以降は拡張属性の保持も既定になっています。落としたいときだけ、--norsrcや--noextattrを明示します。ダウンロードの印だけを落とす--noqtnという指定も用意されています。
APFSでは、実体を複製しない書き方がある
コピーには時間と容量がかかりますが、同じディスクの中で複製するなら、その両方をほぼゼロにできる書き方があります。
cp -c large.mov copy.mov
-cを付けると、clonefileという仕組みが使われます。複製されたファイルは元のファイルとデータの領域を共有し、属性だけを自分のものとして持ちます。どちらかに書き込みが起きた時点で、その部分だけが分かれます。データそのものを読み書きしないため、ファイルの容量が大きくても複製にかかる時間はほとんど変わらず、複製した時点では追加の容量も使いません。
注意点は2つあります。1つは、領域を共有しているため、あとから元のファイルに書き込んだときに空き容量が足りずエラーになる場合があることです。複製した時点では容量を使っていないので、ディスクの空きを見たときの数字と実際に必要な量が食い違います。もう1つは、コピー元とコピー先が別のファイルシステムにある場合や、その仕組みに対応していない保存先の場合です。この場合は自動的に通常のコピーに切り替わるため、コマンドは失敗せずに成功します。速さが出ないときは、保存先が同じディスクかどうかを見ます。
フォルダ階層に対してこの仕組みを直接使うことは、システムの資料で推奨されていません。フォルダを丸ごと複製する場面では、-cではなく-Rの側で書くほうが素直です。
進み具合と、途中で失敗したときの状態
大量のファイルを運ぶと、動いているのか止まっているのか分からなくなります。確かめる方法が2つあります。
1つ目は-vです。コピーしたファイルの名前が1件ずつ表示されます。件数が多い場合は画面が流れますが、どこまで進んだかは分かります。
2つ目は、実行中にControlキーとTキーを同時に押す方法です。いま扱っているファイルの名前と、完了した割合が1行で表示されます。この表示はコマンドを止めずに出るので、大きなファイル1件を運んでいる最中にも使えます。
失敗したときの残り方も押さえておく価値があります。読み書きの途中でエラーが起きた場合、cpはコピー先に途中までのファイルを残します。これは仕様として決められている挙動で、消してしまうと元のファイルも読めない状況で手元の複製まで失うことがあるためです。つまり、コピー先にファイルがあることは、コピーが完了した証拠になりません。完了を確かめるなら、サイズやハッシュ値を突き合わせます。
shasum -a 256 before after
2行が同じ値で返れば、中身は一致しています。1件ずつ確かめる手間はかかりますが、運んだあとで元を消す予定があるなら、この一手を挟む価値があります。
件数が多い場合と、やり直しがある場合の選び分け
cpは1回で終わる複製に向いていますが、回線が不安定な場所や、同じ場所へ何度も反映する作業では別の道具のほうが合います。
| 使う場面 | 向いている道具 | 押さえる指定 |
|---|---|---|
| 1回で終わる複製、同じディスク内 | cp | -i / -R / -a / -c |
| アプリのバンドルやメタデータを保つ | ditto | 既定で保持、落とすときだけ指定 |
| 差分だけ反映、中断からのやり直し | openrsync | --partial / -u / --delete |
| ハードリンクの関係を保つ | tar / pax | まとめて包んでから展開 |
macOSに入っているrsyncは、名前がopenrsyncになっています。中断したところから続ける--partial、コピー先のほうが新しいファイルを飛ばす-u、コピー元に無いファイルをコピー先から消す--delete、拡張属性を運ぶ--extended-attributesなどが用意されています。進み具合を出す--progressもあります。同じフォルダを繰り返し反映する作業では、2回目以降が大きく短くなります。
ただし、消す側の指定は取り違えたときの影響が大きくなります。--deleteを含む行を初めて走らせるときは、実際には書き換えずに結果だけを出す指定を先に付けて、対象の並びを目で読んでから外す順番にします。
対象の取り違えを防ぐ書き方
コピーの事故は、指定の書き方そのものよりも、対象を取り違えたことで起きます。防ぐ手が3つあります。
1つ目は、コピー先の末尾にスラッシュを付けて書くことです。
cp before.txt ~/Backup/
スラッシュがあると、コピー先がフォルダであることを前提に解釈されます。Backupという名前のフォルダが無かった場合、ファイルとして作られるのではなく、そこで止まります。フォルダ名を打ち間違えたときに、意図しないファイルが1つできて終わる事態を避けられます。
2つ目は、対象をまとめて指定するときに、先に数を確かめることです。星印は「0文字以上の任意の並び」を表し、疑問符は「任意の1文字」を表します。
ls *.txt | wc -l
コピーする前に件数を数えておけば、コピー後の件数と突き合わせられます。なお、点で始まる名前は星印の対象に入りません。設定ファイルを運ぶつもりで星印だけを書くと、目的のファイルが対象から漏れます。
3つ目は、名前に空白や括弧が含まれる場合の扱いです。引用符で囲むか、空白の手前にバックスラッシュを書きます。Finderからターミナルへファイルをドラッグすると区切りの記号が自動で付くため、この取り違えは起きません。日本語の名前や、括弧付きの連番が入った名前を扱うときは、打つよりドラッグのほうが確実です。
コピーの前後を1つの窓で見る
コピーの作業で本当に時間を取られるのは、コマンドを打つ部分ではありません。コピー元とコピー先の中身を見比べて、上書きになるものが無いかを確かめる部分です。Finderの窓を2枚並べて数を数え、ターミナルに戻って打ち、結果をまたFinderで確かめる流れになると、往復の回数がそのまま作業時間になります。
フォルダとターミナルとAIが同じ窓にある状態なら、コピー先の中身を見たままコマンドを組み立てられます。返ってきた文面をその場で読めるので、失敗した件数を数え直す手間も減ります。コピーは「対象を決める、上書きになるものを確かめる、実行して結果を突き合わせる」の3手なので、対象の指定と結果の確認が同じ場所でできるほど短く終わります。
道具の側で何ができるかはできることに、Finderや他のファイル管理との違いは他のファイル管理との比較に整理されています。外出先のiPhoneから手元のMacに残した作業を確かめる使い方はiPhone・iPadから続きを、費用の目安は料金にあります。判断に迷いやすい点はよくある質問にまとまっています。
最初に決めておくとよいのは、手で打つときは-i、スクリプトに書くときは-nという使い分けです。この1点を習慣にしておけば、上書きで失う場面はほぼ起きません。そのうえで、同じディスクの中で大きなファイルを複製する場面だけ-cを思い出せば、待ち時間も容量も抑えられます。
よくある質問
cp で上書きしてしまったファイルは戻せますか?
cpの側には元に戻す仕組みがありません。Time Machineのバックアップに入っていれば、その時点の版を取り出せます。バージョン管理の下にあるファイルなら履歴から戻せます。どちらにも無い場合は戻せないため、手で打つときは-iを付けて確認を挟み、自動で走る処理では-nを付けて上書きが起きない形にしておくのが現実的です。
フォルダをコピーしたら、階層が1つずれました。原因は何ですか?
コピー元の末尾にスラッシュが付いていたかどうかです。cp -R work backup と書くとbackupの中にworkというフォルダが作られ、cp -R work/ backup と書くとbackupの直下にworkの中身が展開されます。1文字の違いで結果が変わるため、実行の前にコピー先の中身を一度見ておくと気付けます。
アプリをコピーしたら壊れているため開けませんと出ます。何が原因ですか?
拡張属性が落ちた可能性があります。cpの-Xは拡張属性とリソースフォークを運ばないため、署名の検証が通らなくなります。アプリのバンドルを運ぶときは-Xを外し、Macの構造を前提に作られたdittoを使うほうが無難です。USBメモリに多いFAT形式のボリュームを経由した場合も同じことが起きます。
大きな動画を同じディスク内で複製すると時間がかかります。速くできますか?
cpに-cを付けると、clonefileという仕組みが使われ、データの領域を共有したまま複製が作られます。書き込みが起きた部分だけが分かれる方式なので、複製自体は一瞬で終わり、追加の容量も使いません。別のディスクへのコピーや、対応していない保存先では通常のコピーに切り替わって成功します。