Linux / コマンド / cp - ファイルとディレクトリのコピー

cpはファイルやディレクトリを別のパスにコピーするコマンドです。基本的なコピーから再帰的コピー、権限・時間・リンクの保持、上書き防止までさまざまなオプションを提供しますが、元のファイルと対象の形態を正確に区別する必要があります。

この記事では、GNU Coreutilsのcpを基準に、基本文法、-rと-aの違い、対象ファイルの保護、シンボリックリンクの扱い、大容量コピーの確認方法を説明します。

cpコマンドとは?

通常の cp は、コピー元とは別のファイルとして使えるコピーを作ります。新しいファイルを作る場合は別のinode(ファイルを識別する管理情報)が割り当てられますが、既存のコピー先を上書きする場合はそのinodeが維持されることもあります。コピーオンライト方式の複製では、変更するまでデータブロックを共有するため、必ず全データが別の物理領域に保存されるわけではありません。-l でハードリンクを作る指定も通常のコピーとは異なります。ディレクトリには -R や -a のような再帰オプションが必要です。

基本的な文法

cp [オプション] コピー元 コピー先
cp [オプション] コピー元 ... ディレクトリ
cp [オプション] -t ディレクトリ コピー元 ...

ファイル名やパスに空白がある場合は引用符で囲み、ハイフンで始まる名前は可能であれば--の後に指定します。サポートされるオプションはディストリビューションとGNU Coreutilsのバージョンによって異なる場合があるため、cp --helpとman cpで現在のシステムの説明を確認してください。

cpの基本的な使い方

ファイルを新しい名前でコピーする

2つのパスを指定すると、最初のファイルを2番目のパスにコピーします。

cp report.txt report-backup.txt

複数のファイルをディレクトリにコピーする

複数のコピー元がある場合、最後の引数は既存のディレクトリであるべきです。

cp index.html style.css public/

ディレクトリの再帰的コピー

ディレクトリツリーは -R または -r を付けてコピーします。メタデータの保存が重要な場合、例えばバックアップやデプロイメントなど、 -aを確認してください。

cp -R src src-copy
cp -a app/ app-backup/

コピーしたファイルが同じか確認する

cp は成功しても通常メッセージを出力しません。重要なコピーでは、コピー先が存在することに加え、内容も確認してください。以下は original.txt と copy.txt がまだない練習用ディレクトリで実行します。

printf 'demo\n' > original.txt
cp original.txt copy.txt
cmp -s original.txt copy.txt
echo $?

例の出力は0であり、両方のファイルのバイト内容が同一であることを意味します。ただし、所有権、権限、拡張属性などのメタデータが同一であるかcmpは検証していないため、必要に応じてstatでファイル属性も確認してください。

主なオプション

オプション 説明
-R, -r ディレクトリやサブコンテンツを再帰的にコピーします。
-a, --archive 再帰的にコピーしながら可能な性質やリンク構造を保持すること。
-p モード、所有権とタイムスタンプを可能な範囲で保持します。
-i 既存の対象を上書きする前に確認します。
-n, --no-clobber 既存の対象ファイルを上書きしません。バージョンによる詳細な動作はヘルプで確認してください。
-u, --update 対象がない場合や元がより新しい場合など、条件に応じてコピーします。
-v 処理するファイルを出力します。
-T 対象をディレクトリではなく正確なパスとして扱います。
-t DIR 対象ディレクトリをオプションで先に指定します。
--reflink[=WHEN] サポートされているファイルシステムでコピーオンライトの複製を試みます。

長いオプションは意味を把握しやすく、スクリプトの確認にも役立ちます。ただし、移植性が重要なスクリプトでは対象システムがその GNU 拡張オプションをサポートしているかをまず確認してください。

実践的活用例

上書きを確認または回避する

対話型作業では -i で確認できます。自動化で既存のファイルを保持する必要がある場合は、-n と終了状態、結果ファイルを一緒に確認してください。GNUの現行マニュアルでは -n は非推奨で、スキップ時の終了状態は実装にも依存します。対応版では --update=none は既存ファイルを失敗にせずスキップし、--update=none-fail はスキップを診断して失敗終了にできます。使用前にヘルプで対応を確認してください。例の backup/ は先に作成し、コピー元ファイルも用意します。

cp -iv config.ini backup/
cp -nv *.conf backup/

属性を保持してバックアップする

-a は再帰コピーと共にシンボリックリンク、権限、タイムスタンプなどの保持を試みます。ACL(アクセス制御リスト)、拡張属性、SELinuxのセキュリティラベルおよび所有権は、ファイルシステムと権限によって完全には保持されない場合があります。

sudo cp -a /etc/myapp/ /backup/myapp/
cp -a --preserve=all source/ destination/

コピー結果の検証

重要なファイルはサイズだけでなく、チェックサムやファイル数を比較してください。作業中に元のファイルが変更される環境では、一貫したスナップショットや専用の同期ツールが必要になる場合があります。

sha256sum source.img copied.img
diff -qr source-dir copied-dir

cp と関連コマンドの比較

コマンド・方法 主な役割 適した状況
cp ローカルファイル・ディレクトリのコピー 簡単で明確なコピー作業
mv パスの移動または名前の変更 元の場所に残す必要がないとき
rsync 増分・リモート同期と細かい除外ルール 大規模な繰り返しコピーやネットワーク転送
install コピーと同時に権限・所有権を設定 プログラムのインストールと配布段階

使用する際の注意点

対象ディレクトリの意味を確認する

cp source dirでdirが存在するディレクトリかどうかによって、結果のパスが変わります。スクリプトでは-Tや-tで意図を明確にすることができます。

-aは完全なバックアップを保証しません

ファイルシステムの機能、権限、開かれているファイルや実行中の変更のため、すべての状態が保持されるとは断定できません。サービスデータはアプリケーションに適したバックアップ手順を使用してください。

シェルグロブと隠しファイルを区別する

cp -a source/* dest/の*は一般的に隠し項目を除きます。ディレクトリ自体の内容を保持するには、パスの表記と含める範囲を確認してください。

FAQ

ディレクトリをコピーする際に-rと-aのどちらを使用すべきですか?

単純な再帰コピーは-Rに対して、権限・日時・シンボリックリンク構造など可能な限りの属性を保持するには-aが適しています。

既存のファイルを上書きしたくない場合は、どうすればよいですか?

GNU cpでは-nを使用できます。重要な自動化では、結果とインストールされているバージョンの動作も確認してください。

cp -a source/ dest/は何をコピーしますか?

source がディレクトリの場合、dest がなければその名前でコピーされ、配下に元の内容が入ります。dest が既にディレクトリとしてあれば、通常は dest/source/ ができます。末尾の / だけでは「中身だけ」の指定になりません。隠し項目も含め中身を既存のコピー先へ入れる場合は cp -a source/. dest/ のように範囲を明示し、練習用の場所で確認してください。

コピーが正確だったかどうかはどう確認しますか?

ファイルはチェックサムで、ディレクトリはdiff -qrやファイルリスト・数を比較できます。重要なバックアップは復元テストまで行うべきです。

参考資料