AWS

aws s3 cpの使い方|再帰コピー・フィルタ・ストリーム転送と終了コードの実装手順

aws s3 cpの使い方|再帰コピー・フィルタ・ストリーム転送と終了コードの実装手順

aws s3 cpは1行で動くぶん、細かな挙動を知らないまま本番のスクリプトに入りがちなコマンドです。コピー先の末尾にスラッシュを付けるかどうかでオブジェクト名が変わる、--excludeと--includeは書く順番で結果が逆になる、一部のファイルだけ失敗しても終了コードが0にならない。この記事では、こうした挙動をAWS CLI 2.37系(2026年10月時点の公式リファレンス表記)の仕様に沿って整理し、実行できるコマンドで示します。バケットの作成や権限設計といったS3全体の手順はAWS S3の使い方|CLIでのバケット作成から権限設計・署名付きURLまでの実装手順にまとめてあるため、本記事はcpの引数と挙動に絞ります。

まとめ|aws s3 cpで事故を防ぐために先に押さえる5つの挙動

先に結論を置きます。aws s3 cpを自動化に組み込む前に確認しておきたいのは、次の5点です。

  • コピー先の末尾が/ならコピー元の名前を引き継ぎ、無ければ指定した名前で保存される
  • パスにワイルドカードは書けず、絞り込みは--excludeと--includeで行う。後に書いたフィルタが優先される
  • コピー元に-を指定すると標準入力からアップロードでき、50GBを超えるストリームは--expected-sizeが必要になる
  • 新しく作るバケットはACLが無効なので、--acl public-readのような指定は400エラーで失敗する
  • 終了コード1は転送失敗、2はスキップや構文エラーを示す。0以外をまとめて失敗扱いにすると原因を取り違える

どれも公式ドキュメントに書かれている仕様ですが、入門記事ではほとんど触れられていません。以降で1つずつ手順に落とします。

aws s3 cpの書式と末尾スラッシュで変わるコピー先の名前の決まり方

前提として、AWS CLI v2が入っていて認証が通っている状態から始めます。導入とSSO認証の設定はAWS CLIの導入と運用|v2の設定・SSO認証・v1サポート終了への移行手順を参照してください。

アップロード・ダウンロード・S3間コピーの3方向を1つの書式で書く

cpのリファレンスにある通り、書式はaws s3 cp <コピー元> <コピー先> [オプション]の1種類だけです。コピー元とコピー先のどちらにs3://を書くかで、アップロード、ダウンロード、S3間コピーが切り替わります。

# ローカルからS3へアップロード
aws s3 cp ./report.csv s3://example-bucket/reports/report.csv

# S3からローカルへダウンロード
aws s3 cp s3://example-bucket/reports/report.csv ./report.csv

# S3からS3へコピー(ローカルを経由しない)
aws s3 cp s3://example-bucket/reports/report.csv s3://example-archive/2026/report.csv

実行するとupload:・download:・copy:のいずれかが1行ずつ表示されます。S3間コピーはサーバー側のCopyObjectで処理されるため、手元の回線を通りません。

末尾の/の有無でオブジェクト名が変わるパス引数の規則

s3コマンド共通のリファレンスには、コピー先の末尾がスラッシュならディレクトリやプレフィックスとして扱い、コピー元の名前を引き継ぐと書かれています。スラッシュが無ければ、指定した文字列がそのままオブジェクト名になります。

# 末尾スラッシュあり:s3://example-bucket/backup/report.csv になる
aws s3 cp ./report.csv s3://example-bucket/backup/

# 末尾スラッシュなし:s3://example-bucket/backup という名前の1オブジェクトになる
aws s3 cp ./report.csv s3://example-bucket/backup

後者は「backupフォルダに入れたつもりが、backupという名前のファイルができていた」という取り違えの典型です。S3のs3://側は常に/、ローカル側はOSの区切り文字を使う点も同じページに明記されています。

–recursiveと–exclude・–includeによる対象指定と評価順

複数ファイルを扱うときに迷うのがここです。aws s3 cp ./logs/*.log s3://...のようなシェルのワイルドカードは、S3側のパスでは解釈されません。

パスにワイルドカードを書けない場合に対象を絞るフィルタの4記号

ディレクトリやプレフィックス配下をまとめて扱うには--recursiveを付け、対象を--excludeと--includeで絞ります。s3コマンド共通のリファレンスで使える記号は*(任意の文字列)、?(任意の1文字)、[sequence](列挙した文字のいずれか)、[!sequence](列挙した文字以外)の4つです。

フィルタはコピー元ディレクトリを起点に評価されます。--exclude ".git/*"と書けばコピー元直下の.git配下が外れます。コピー元が単一ファイルのときは、そのファイルを含むディレクトリが起点です。

後に書いたフィルタが勝つ評価順と.logだけを転送するコマンド

同じページに「コマンドの後ろに現れたフィルタが、前に現れたフィルタより優先される」と書かれています。つまり順番を入れ替えると結果が逆になります。

# .logだけを転送する(全部除外してから.logを戻す)
aws s3 cp ./logs s3://example-bucket/logs/ \
  --recursive --exclude "*" --include "*.log" --dryrun

# 順番を逆にすると、最後の --exclude "*" が勝って何も転送されない
aws s3 cp ./logs s3://example-bucket/logs/ \
  --recursive --include "*.log" --exclude "*" --dryrun

両方に--dryrunを付けてあります。実際には転送せず、実行されるはずの操作だけを(dryrun) upload:の形で表示するオプションです。フィルタを書いたら、本番の前に必ずこれで対象一覧を目で確かめてください。2本目のコマンドは何も表示されずに終わるので、順番の誤りにその場で気づけます。

–no-overwriteの上書き回避と–case-conflictの衝突対処

現行のリファレンスには、転送先に同名のファイルがあればスキップする--no-overwriteがあります。既存のオブジェクトを守りながら、足りないものだけを補充する用途に向きます。

WindowsやmacOSへダウンロードするときは--case-conflictも確認してください。S3のキーは大文字と小文字を区別しますが、これらのOSの標準的なファイルシステムは区別しません。Report.csvとreport.csvが両方あると後から落ちたほうが上書きします。既定値はignore(衝突を無視してダウンロード)で、error・warn・skipに変えられます。

標準入出力のストリーム転送と50GBを超えるときの–expected-size指定

ここからは入門記事で扱われていない機能です。一時ファイルを作らずにパイプで転送できます。

コピー元に-を指定してダンプを一時ファイル無しでアップロードする

cpのリファレンスでは、コピー元に-を書くと標準入力から、コピー先に-を書くと標準出力へ転送すると定義されています。データベースのダンプを圧縮しながらそのまま保存する例です。

# ダンプを圧縮しながらS3へ直接アップロード(ディスクに一時ファイルを残さない)
pg_dump --format=custom appdb | gzip \
  | aws s3 cp - s3://example-backup/db/appdb-20261001.dump.gz

# S3のファイルを標準出力に流して、ダウンロードせずに先頭だけ確認
aws s3 cp s3://example-bucket/logs/app-20261001.log - | head -n 20

ディスク容量の小さいバッチサーバーで大きなファイルを扱う場合に効きます。ただし、標準出力へのダウンロードは--recursiveと組み合わせられません。対象は常に1オブジェクトです。

パート数1万の上限で50GB超のストリームが途中で失敗する仕組み

ストリームではCLIが全体のサイズを事前に知りません。そのため、既定のチャンクサイズのまま分割していくと、マルチパートアップロードの上限である1アップロードあたり10,000パートに届いた時点で失敗します。リファレンスは、50GBを超えるストリームでは--expected-sizeにバイト数を渡すよう求めています。

# 約60GBのストリームを送る場合はバイト数で予告する
tar -cf - ./dataset | aws s3 cp - s3://example-bucket/dataset.tar \
  --expected-size 64424509440

サイズが分かればCLIはパートを大きく取り直せます。パート1つの大きさは5MiB〜5GiB、1オブジェクトの最大サイズは48.8TiBで、これを超える分割はできません。正確なバイト数が出せないときは、少し大きめの見積もりを渡しておけば上限内に収まります。

ストレージクラス・暗号化・メタデータをcpの引数で指定する実行手順

アップロードと同時に、保管クラス・暗号化・HTTPヘッダを決められます。後からs3apiで付け直すより手数が減ります。

–storage-classと–sseをアップロード時に付ける書き方

--storage-classに指定できる値は、リファレンス上でSTANDARD、REDUCED_REDUNDANCY、STANDARD_IA、ONEZONE_IA、INTELLIGENT_TIERING、GLACIER、DEEP_ARCHIVE、GLACIER_IRの8種類です。暗号化は--sseにAES256かaws:kmsを渡し、カスタマー管理キーを使うときだけ--sse-kms-key-idを足します。

aws s3 cp ./archive-2025.zip s3://example-archive/2025/ \
  --storage-class GLACIER_IR \
  --sse aws:kms --sse-kms-key-id alias/example-archive-key \
  --metadata project=example,owner=infra

aws s3 cp ./dist/app.js s3://example-assets/static/app.js \
  --content-type "application/javascript" \
  --cache-control "public, max-age=31536000, immutable"

アーカイブ系のクラスは最小保存期間と取り出し料金が付くため、少量の短期ファイルを直接入れると割高になります。クラスごとの考え方はAmazon S3とは?オブジェクトストレージの仕組み・ストレージクラスと料金・採用判断を実装者目線で解説に、取り出し時間の違いはAmazon S3 Glacierとは?3つのアーカイブストレージクラスと取り出し時間・料金・採用判断を実装者目線で解説にあります。

MIMEタイプの推測と–copy-propsで決まるS3間コピーのメタデータ

アップロード時、CLIは拡張子からMIMEタイプを推測してContent-Typeに入れます。--content-typeを指定すれば推測値を上書きでき、--no-guess-mime-typeで推測そのものを止められます。静的サイトのファイルを配る場合は、拡張子の無いファイルに意図しない型が付いていないかを確認してください。

S3間コピーでは--copy-propsがメタデータの引き継ぎを決めます。既定のdefaultでコピーされる対象は、タグとContent-Type・Cache-Control・ユーザー定義メタデータなどです。noneは何もコピーせず、allはdefaultの範囲に加えてアノテーションも引き継ぎます。マルチパートで処理される大きなオブジェクトでは、defaultがHeadObjectやGetObjectTagging、PutObjectTaggingを追加で呼ぶとリファレンスに書かれており、タグの読み書き権限が無いロールで失敗するのは、この追加呼び出しが原因です。--metadata-directiveを指定すると--copy-propsは無効になる点にも注意が要ります。リージョンをまたぐS3間コピーでは、コピー元のリージョンを--source-regionで渡します(--regionはコピー先を指します)。

ACL無効が既定になった後のバケットで–aclが400で失敗する原因と対処

古い記事の--acl public-readをそのまま使うと、今のバケットでは失敗します。原因はS3側の既定値の変更です。

新規バケットのACL無効の既定値と指定時に400エラーが返る条件

オブジェクト所有権のドキュメントによると、新しく作るバケットのObject Ownershipは既定で「Bucket owner enforced」で、ACLはすべて無効です。この状態のバケットが受け付けるのは、ACLを指定しないPUTか、bucket-owner-full-controlを指定したPUTだけです。それ以外のACLを付けたリクエストは400エラーになり、エラーコードAccessControlListNotSupportedが返ります。

対処は、ACLで公開する設計をやめてバケットポリシーで権限を渡すことです。公開配信が目的なら、CloudFrontを前段に置く構成が素直でしょう。権限の組み立てはAWS IAMとは?仕組み・ユーザー/ロール/ポリシーの違いと権限設計のベストプラクティスを実装者目線で解説を参照してください。

他アカウントのバケットへ書き込む既存スクリプトに残せる唯一のACL指定

例外として、他アカウントのバケットへ書き込む既存のスクリプトは--acl bucket-owner-full-controlを付けたままでも動きます。ACLが無効なバケットでもこの指定は受け付けられ、書き込んだオブジェクトの所有者は書き込み先のバケット所有者です。なお--aclを使う場合、実行するIAMプリンシパルにs3:PutObjectAclの権限が要ることもリファレンスに書かれています。

終了コード1と2を区別してシェルスクリプトとCIで失敗を検知する書き方

aws s3 cpをバッチやCIに組み込むなら、終了コードの意味を押さえておく必要があります。

終了コード0・1・2・252〜255が示す失敗の種類と確認方法

終了コードのドキュメントにある定義を表にまとめます。

コード 意味
0 成功
1 s3コマンドで1件以上の転送が失敗
2 構文の解析失敗、または一部ファイルのスキップ
130 Ctrl-Cによる中断
252 構文や引数の値が不正
253 設定や認証情報が無い
254 サービスがエラーを返した
255 その他の実行時エラー

注意したいのは2です。s3コマンドでは、存在しないファイル、読み取り権限の無いファイル、FIFOやソケットなどがスキップされたときに2が返り、ほかのファイルは正常に転送されています。全件の失敗とは限りません。

夜間バックアップでスキップを許容するか失敗にするかを分岐させるシェルの書き方

夜間バックアップのように「スキップは警告、転送失敗は異常」と分けたい場合は、終了コードで分岐させます。

#!/usr/bin/env bash
set -u
aws s3 cp ./export s3://example-backup/export/ --recursive --only-show-errors
rc=$?
case "$rc" in
  0) echo "転送完了" ;;
  2) echo "一部ファイルをスキップしました(権限や特殊ファイルを確認)" >&2 ;;
  1) echo "転送に失敗したファイルがあります" >&2; exit 1 ;;
  *) echo "CLIの実行エラー rc=$rc" >&2; exit "$rc" ;;
esac

--only-show-errorsはエラーと警告だけを出すオプションで、ログが進捗表示で埋まるのを防げます。PowerShellで同じ終了コードの判定に使う変数は、$LASTEXITCODEです。Glacier系のオブジェクトを含む再帰コピーでは、取り出せないオブジェクトの警告で2が返ることがあります。--ignore-glacier-warningsを付ければ警告が消え、終了コードも2になりません。

転送が遅いときに見直すマルチパート設定とCRT転送クライアントの条件

大量のファイルや大きなファイルで時間がかかる場合、触るのはコマンドの引数ではなく~/.aws/configの転送設定です。

同時リクエスト10・閾値8MBの既定値を変える設定ファイルの例

CLIのS3設定の既定値は、同時リクエスト数10、キュー1,000、マルチパート閾値8MB、チャンクサイズ8MB、帯域上限なしです。小さいファイルが大量にあるなら同時リクエスト数を、大きいファイルが少数ならチャンクサイズを上げます。

[profile batch]
region = ap-northeast-1
s3 =
  max_concurrent_requests = 32
  multipart_threshold = 64MB
  multipart_chunksize = 32MB
  max_bandwidth = 200MB/s

同時リクエストを増やすと、そのぶんCPUとネットワークを食います。業務時間中に共有回線で動かすならmax_bandwidthで上限を付けておくと、ほかの通信を圧迫しません。PUTやGETの回数はリクエスト料金に直結するため、細かいファイルを大量に転送する前にS3の料金を実額で計算する|東京リージョンの単価内訳とコストを下げる設定手順で単価を確認しておくと安心です。

preferred_transfer_clientのcrt切替条件と無視される設定

同じページによると、preferred_transfer_clientの既定はautoです。S3間コピーではないこと、Linux上のEC2で動いていること、対象のインスタンスタイプであること、ほかにCRTを使うCLIプロセスが動いていないこと。これらを満たすと、C言語ベースのCRT転送クライアントへ自動で切り替わります。

CRTが使われるとmax_queue_sizeとmax_bandwidthは無視され、帯域はtarget_bandwidthで指定します。手元のPCでは効いていた帯域制限がEC2上で効かない、という差はここから生まれます。挙動を揃えたいならpreferred_transfer_client = classicを明示してください。

転送の正しさについては、オブジェクト整合性のドキュメントにある通り、AWSのクライアントはアップロード時にチェックサムを計算して送り、S3側で照合します。既定のアルゴリズムはCRC64NVMEです。ダウンロード時にも検証したい場合は--checksum-mode ENABLEDを付けます。

aws s3 cpとsync・S3 Batch Operationsの選択基準

最後に、cpを選ぶ条件と別の手段へ寄せる場面を線引きします。

受託開発の現場でcpを第一候補にする条件と見送るべき3つの場面

第一候補にする条件は、転送対象がその都度決まること、1回きりか毎回すべて送り直してよいこと、パイプで受け渡したいことの3つです。ダンプの退避、ビルド成果物の配置、調査用の一時ダウンロードがこれに当たります。

見送る場面は3つあります。1つ目は、同じディレクトリを繰り返し送る運用です。syncのリファレンスにある通りsyncはサイズと更新時刻で差分を判定するため、変更分だけを送れます。2つ目は、数百万件単位のオブジェクトを一度に扱う場合です。CLIの1プロセスで回すより、S3 Batch Operationsに任せたほうが再実行と進捗の管理が楽になります。3つ目は、アプリケーションがファイルシステムとして読み書きしたい場合です。S3 Filesとは:S3バケットをNFSでマウントする手順とEFS・Mountpointとの使い分けのようにマウントする構成を検討します。

転送設計を含めてバックアップや配信の構成を固めたい場合は、インフラ構築(AWS・Google Cloud・Azure)で要件整理から対応しています。

よくある質問

aws s3 cpについて検索されている質問に、公式ドキュメントの記載をもとに答えます。

aws s3 cpでワイルドカードを使って複数ファイルを指定できますか?

パスにワイルドカードは書けません。--recursiveでディレクトリごと対象にしたうえで、--exclude "*" --include "*.csv"のようにフィルタで絞ります。後に書いたフィルタが優先されるため、除外を先、取り込みを後に書くのが基本形です。

aws s3 cpとaws s3 syncはどう使い分けますか?

cpは指定したものを毎回コピーし、syncはサイズと更新時刻を比べて差分だけを転送します。1回きりの転送やパイプでの受け渡しはcp、同じディレクトリを繰り返し反映する運用はsyncが向きます。syncに--deleteを付けると転送先にしか無いファイルを消すので、先に--dryrunで確認してください。

aws s3 cpでフォルダごとダウンロードするにはどうすればよいですか?

aws s3 cp s3://example-bucket/reports/ ./reports --recursiveのように、コピー元のプレフィックスに--recursiveを付けます。WindowsやmacOSへ落とすときは、大文字小文字だけが違うキーが上書きし合わないよう--case-conflict warnなどの指定も検討してください。

aws s3 cpで上書きせずに足りないファイルだけを送れますか?

現行のAWS CLI v2には--no-overwriteがあり、転送先に存在しないファイルだけを送ります。古いバージョンでは使えない場合があるため、aws --versionで版を確認し、リファレンスに載っているかを照らしてから使ってください。

aws s3 cpが一部だけ成功して終了コード2になるのはなぜですか?

s3コマンドの終了コード2は、存在しないファイル、読み取り権限の無いファイル、FIFOやソケットなどがスキップされたことを示します。スキップされたファイル以外は正常に転送された状態です。転送そのものが失敗した場合は1が返るので、スクリプトでは1と2を分けて扱うと原因を切り分けやすくなります。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2024.07.11 テックブログ PEP8とは?Pythonコーディング規約の基本ルールとチェックツール(Ruff対応)
  2. 2026.09.28 テックブログ タイムズカーの不正アクセスと免許証画像160万件の流出|退会者まで残さない保管設計
  3. 2026.09.27 コラム 法定調書合計表とは?令和8年分の書き方と提出義務、給与・支払データからの集計自動化
  4. 2026.03.24 テックブログ EARS記法とは?5つの基本型と複合型の書き方・日本語例文・Kiroでの使い方
  5. 2026.09.30 テックブログ OpenAI Dotsとは?常時稼働エージェントの権限設計と自社システム接続【2026年9月】

RELATED POSTS 関連記事

目次