はじめに (対象読者・この記事でわかること)

この記事は、LinuxやUNIX系のコマンドライン操作に慣れてきたものの、ファイルコピーの際に「なぜかパーミッションが変わってしまう」「タイムスタンプが更新されて困る」といった経験を持つ読者の方、またファイルやディレクトリの属性を正確に引き継ぎたいと考えている方を対象としています。

この記事を読むことで、cpコマンドの-aオプションと-pオプションの具体的な違いと、それぞれのオプションがどのようなファイル属性を保持するのかが明確にわかります。また、これらのオプションをどのような場面で使い分けるべきか、そして正しく利用するための方法を習得できます。日々の作業におけるファイル管理の質を向上させ、予期せぬ問題を防ぐための一助となるでしょう。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Linux/UNIXの基本的なコマンド操作(ls, cd, mkdir, cpなど) - ファイルのパーミッション(読み書き実行権限)の概念 - タイムスタンプ(ファイルの作成時刻、更新時刻、アクセス時刻など)の概念

なぜファイルの「属性」を保持する必要があるのか?

cpコマンドは、ファイルをコピーする最も基本的なコマンドですが、何もオプションを付けずに実行した場合、単にファイルの内容だけが新しい場所に複製されます。この際、新しいファイルのタイムスタンプ(作成時刻や更新時刻)はコピーが実行された日時になり、パーミッション(読み書き実行権限)も通常は現在のユーザーのデフォルト設定(umaskによる)に従って付与されます。

しかし、多くの場合、単に内容をコピーするだけでは不十分です。 例えば、以下のようなシナリオを考えてみましょう。

  • システムバックアップ: サーバーの設定ファイルやWebコンテンツをバックアップする際、元のパーミッションやタイムスタンプが保持されていないと、復元時に正しく動作しない可能性があります。特にWebサーバーのコンテンツでは、パーミッションが異なるとアクセスエラーが発生することも少なくありません。
  • 開発環境の複製: プロジェクトディレクトリを別の場所にコピーする際、ファイルの更新時刻が全てリセットされてしまうと、makeなどのビルドツールが不必要に全ファイルを再ビルドしてしまうことがあります。
  • タイムスタンプを条件とする処理: 特定のタイムスタンプを持つファイルを処理するスクリプトがある場合、コピーによってタイムスタンプが変わってしまうと、スクリプトが誤動作する原因になります。
  • 所有者/グループの維持: 特定のユーザーやグループに所有されているファイルをそのままの状態でコピーしたい場合があります。

これらの問題を解決するために、cpコマンドにはファイルのメタデータ(属性)を保持するためのオプション、 specifically -p (preserve) と -a (archive) が用意されています。これらのオプションを適切に使うことで、ファイルやディレクトリを「現状のまま」正確に複製することが可能になります。

cp -acp -pの徹底比較と使用例

ここでは、cpコマンドの-pオプションと-aオプションについて、それぞれの機能と具体的な使用例を交えて詳しく解説します。

まずは基本のcpコマンド

オプションなしでcpコマンドを実行すると、ファイルのタイムスタンプとパーミッションはコピー時にリセットされます。

Bash
# テスト用のファイルとディレクトリを作成 mkdir original_test_dir echo "Original content 1" > original_test_dir/file1.txt echo "Original content 2" > original_test_dir/file2.txt chmod 644 original_test_dir/file1.txt # パーミッションを設定 chmod 755 original_test_dir/file2.txt # 異なるパーミッションを設定 sleep 1 # タイムスタンプに差をつけるため少し待つ touch -d "2 days ago" original_test_dir/file1.txt # 過去のタイムスタンプに設定 # 元のファイルの情報を確認 ls -l original_test_dir/ # 出力例: # -rw-r--r-- 1 user group 17 Jul 27 10:00 file1.txt # -rwxr-xr-x 1 user group 17 Jul 29 10:00 file2.txt # オプションなしでコピー cp original_test_dir/file1.txt no_option_copy.txt # コピー後のファイルの情報を確認 ls -l no_option_copy.txt # 出力例: # -rw-r--r-- 1 user group 17 Jul 29 10:05 no_option_copy.txt (パーミッション、タイムスタンプが変更される)

上記例では、no_option_copy.txtのタイムスタンプとパーミッションが、コピー実行時のものに更新されていることがわかります。

cp -pオプションの詳細

  • -p (preserve) オプション: 「preserve」は「保持する」という意味です。このオプションは、コピー元ファイルのタイムスタンプ(更新時刻、アクセス時刻)パーミッション(読み書き実行権限)、そして可能な場合はユーザーIDとグループIDを保持してコピー先に適用します。

  • 保持される主な属性:

    • ファイルの内容
    • タイムスタンプ (mtime: 最終更新時刻, atime: 最終アクセス時刻)
    • パーミッション (chmodで設定される権限)
    • 所有者 (ユーザーID)
    • グループ (グループID)
    • 注意点: 所有者とグループIDを保持するには、通常root権限が必要です。一般ユーザーが実行した場合、自身のIDでファイルを作成し、他の属性のみ保持しようとします。
  • 使用シーン:

    • 個別の設定ファイルやログファイルをバックアップする際に、元の更新日時やアクセス権限を保持したい場合。
    • プログラムの実行ファイルなどをコピーする際に、実行権限を維持したい場合。
    • 少数のファイルをコピーする際に、基本的なメタデータを維持したい場合。
  • コマンド例: bash cp -p original_test_dir/file1.txt preserve_copy.txt ls -l original_test_dir/file1.txt preserve_copy.txt # 出力例: # -rw-r--r-- 1 user group 17 Jul 27 10:00 original_test_dir/file1.txt # -rw-r--r-- 1 user group 17 Jul 27 10:00 preserve_copy.txt # -> タイムスタンプとパーミッションが元のファイルと全く同じになっていることが確認できます。 ディレクトリをコピーする場合は、-Rオプションと組み合わせて cp -R -p source_dir/ dest_dir/ のように使います。

cp -aオプションの詳細

  • -a (archive) オプション: 「archive」は「アーカイブする」という意味で、ファイルやディレクトリを丸ごと、そのすべての属性を含めて複製する際に使用します。これは、cp -dR --preserve=all のショートカットです。

  • 保持される主な属性:

    • -d: シンボリックリンクを「シンボリックリンクとして」コピーします(リンク先のファイルではなく)。
    • -R: ディレクトリを再帰的にコピーします(--recursive)。
    • --preserve=all: 可能な限りすべてのファイル属性を保持します。具体的には、以下のものが含まれます。
      • ファイルの内容
      • タイムスタンプ (mtime, atime)
      • パーミッション
      • 所有者 (ユーザーID)
      • グループ (グループID)
      • コンテキスト (SELinuxコンテキストなど)
      • 拡張属性 (ACLsなど)
  • 使用シーン:

    • サーバー環境の丸ごとバックアップや、Webサイトのコンテンツディレクトリを別の場所に完全にコピーする際。
    • 開発プロジェクトのディレクトリを、ファイルのリンク構造や権限も含めて完全に複製したい場合。
    • システム上でファイルを移動・コピーする際に、ACLやSELinuxコンテキストなどの詳細な属性も維持する必要がある場合。
  • コマンド例: original_test_dirにシンボリックリンクを追加し、-aオプションの挙動を確認します。

    ```bash

    シンボリックリンクを含むディレクトリを作成

    mkdir -p original_archive_dir echo "This is content in data.txt" > original_archive_dir/data.txt ln -s data.txt original_archive_dir/link_to_data.txt chmod 600 original_archive_dir/data.txt touch -d "1 month ago" original_archive_dir/data.txt

    ls -l original_archive_dir/

    出力例:

    -rw------- 1 user group 28 Jun 29 10:00 data.txt

    lrwxrwxrwx 1 user group 8 Jul 29 10:10 link_to_data.txt -> data.txt

    -a オプションでコピー

    cp -a original_archive_dir/ archive_copy_dir/

    コピー後のディレクトリの内容を確認

    ls -l archive_copy_dir/

    出力例:

    -rw------- 1 user group 28 Jun 29 10:00 data.txt

    lrwxrwxrwx 1 user group 8 Jul 29 10:10 link_to_data.txt -> data.txt

    -> data.txtのパーミッションとタイムスタンプ、link_to_data.txtがシンボリックリンクとして保持されています。

    -R -p オプションでコピーした場合と比較 (シンボリックリンクの扱いの違い)

    mkdir recursive_preserve_copy_dir cp -R -p original_archive_dir/ recursive_preserve_copy_dir/

    ls -l recursive_preserve_copy_dir/original_archive_dir/

    出力例:

    -rw------- 1 user group 28 Jun 29 10:00 data.txt

    -rw------- 1 user group 28 Jun 29 10:00 link_to_data.txt

    -> link_to_data.txt がシンボリックリンクではなく、リンク先のdata.txtの内容を持つ「通常のファイル」としてコピーされています。

    `` 上記の例から、-aオプションがシンボリックリンクを「リンクとして」保持するのに対し、-R -pオプションはデフォルトでリンク先の内容をコピーしようとすることがわかります。この点が、-a`オプションがアーカイブコピーに適している大きな理由の一つです。

まとめ:使い分けの指針

  • cp -p:

    • 個別のファイルや少数のファイルをコピーし、基本的なメタデータ(パーミッション、タイムスタンプ、ユーザー/グループID)だけ保持したい場合に最適です。
    • ディレクトリをコピーする場合は、-Rオプションと組み合わせて cp -R -p のように使用する必要があります。
    • シンボリックリンクはデフォルトでリンク先をコピーしようとするため、注意が必要です。
  • cp -a:

    • ディレクトリ全体を、その内部構造、ファイル属性(パーミッション、タイムスタンプ、所有者/グループ)、シンボリックリンクの特性、さらには拡張属性(ACL、SELinuxコンテキストなど)も含めて完全に複製したい場合に最適です。
    • システムバックアップ、開発環境の丸ごと複製、Webサイトコンテンツの移行など、最も包括的なコピーが必要な場合に選択すべきオプションです。

ハマった点やエラー解決

所有者/グループが保持されない

cp -pcp -aを使っても、ファイルやディレクトリの所有者(ユーザーID)やグループ(グループID)が元のものと異なるユーザーでコピー先に設定されることがあります。これは、一般ユーザーが他人の所有権を持つファイルを自由に作成できないというセキュリティ上の制約によるものです。

解決策: - ファイルをコピーする際に、sudoコマンドを使ってrootユーザーとして実行します。これにより、元の所有者やグループIDを正確に保持できます。 bash sudo cp -a /path/to/source_dir/ /path/to/destination_dir/ - root権限でコピーできない場合や、特定のユーザー/グループに変更したい場合は、コピー後にchownコマンドで手動で所有者やグループを変更します。 bash cp -a /path/to/source_dir/ /path/to/destination_dir/ sudo chown -R new_user:new_group /path/to/destination_dir/

シンボリックリンクの挙動の違い

前述の例で示したように、cp -R -pcp -aではシンボリックリンクの扱いが異なります。cp -R -pはデフォルトでリンク先をコピーしようとしますが、cp -aはリンク自体をコピーします。意図しない挙動を防ぐために、この違いを理解しておくことが重要です。

解決策: - シンボリックリンクを「リンクとして」コピーしたい場合は、cp -aを使用するのが最も確実です。 - または、cpコマンドに-P(大文字のP)オプションを追加すると、シンボリックリンクのリンク先を辿らずにリンク自体をコピーするようになります。これは-aに含まれる-dと同じ挙動です。 bash cp -R -p -P original_archive_dir/ recursive_preserve_P_copy_dir/ # これでcp -a と同様にシンボリックリンクが保持される

まとめ

本記事では、cpコマンドの-pオプションと-aオプションの具体的な違いと、それぞれの使用シーンについて解説しました。

  • cp -p: タイムスタンプ、パーミッション、ユーザー/グループIDなど、基本的なファイル属性を保持します。個別のファイルや少数のファイルのコピーに適しており、ディレクトリの場合は-Rオプションとの併用が必要です。
  • cp -a: -pの機能に加えて、ディレクトリの再帰的コピー、シンボリックリンクのリンクとしての保持、ACLやSELinuxコンテキストなどの拡張属性も保持する、包括的なアーカイブコピーを行います。システムバックアップや開発環境の完全な複製に最適なオプションです。

これらのオプションを適切に使い分けることで、ファイルを単にコピーするだけでなく、その「履歴」や「特性」も正確に引き継ぐことが可能になります。これにより、予期せぬパーミッションエラーや不必要な再ビルドなどを防ぎ、より堅牢で効率的なファイル管理を実現できるでしょう。

この記事を通して、cpコマンドのより高度な活用方法を理解し、日々のコマンドライン操作をより効果的に行えるようになったはずです。今後は、ファイル同期や差分バックアップに強力なrsyncコマンドのように、さらに高度なファイル操作ツールについても記事にする予定です。

参考資料