- AWS
aws s3コマンド一覧|cp・sync・ls実行例とオプション早見表
aws s3 コマンドとは、AWS CLI に含まれる Amazon S3 操作用の「高レベルコマンド」で、cp・sync・mv・rm・ls・mb・rb・presign・website の 9 つのサブコマンドで構成されています。 Linux の cp や ls と同じ感覚で「ファイルを上げる・落とす・一覧する・消す」ができ、ディレクトリ単位の転送や差分同期(sync)、並列アップロードまで CLI が面倒を見てくれます。一方で「cp と sync はどちらを使うのか」「--exclude と --include の順序で結果が変わる」「rm に --recursive を付け忘れると消えない」など、知らないと手が止まるポイントもいくつかあります。
この記事では、AWS CLI v1(1.46.1)を、ローカルに立てた S3 互換サーバー(moto_server 5.2.3)に対して実際に実行した出力を載せながら、9 つのコマンドの逆引き表、cp・sync・mv の使い分け表、オプションの目的別早見表、aws s3 と aws s3api の違い、AccessDenied・NoSuchBucket・InvalidAccessKeyId など実際に出るエラー文と対処、大容量転送の設定までをまとめました。本物の AWS アカウントは使っていないので、料金や実データを気にせず同じ手順を手元で再現できます。
aws s3 コマンドの早見表(やりたいこと → コマンド)
まず「やりたいこと」からコマンドを引ける表です。 s3://バケット名/キー の形で S3 側のパスを書き、ローカル側は普通のパスを書きます。--recursive が要るのは cp・mv・rm の 3 つだけで、sync・ls・mb・rb は常にディレクトリ(プレフィックス)単位で動きます。
| やりたいこと | コマンド | 補足 |
|---|---|---|
| バケット一覧を見る | aws s3 ls |
引数なしでバケット一覧 |
| バケット直下を見る | aws s3 ls s3://bucket/ |
サブフォルダは PRE と表示 |
| 配下を全部見る(サイズ合計も) | aws s3 ls s3://bucket/ --recursive --human-readable --summarize |
末尾に Total Objects / Total Size |
| ファイルを 1 つアップロード | aws s3 cp ./a.txt s3://bucket/ |
末尾 / で元の名前を保つ |
| 名前を変えてアップロード | aws s3 cp ./a.txt s3://bucket/dir/b.txt |
末尾 / なしで名前指定 |
| フォルダごとアップロード | aws s3 cp ./dir/ s3://bucket/dir/ --recursive |
毎回すべて転送 |
| フォルダの差分だけ転送 | aws s3 sync ./dir/ s3://bucket/dir/ |
新規・更新分のみ |
| 削除も含めて完全に同期 | aws s3 sync ./dir/ s3://bucket/dir/ --delete |
転送先だけにあるものを削除 |
| ダウンロード(1 つ) | aws s3 cp s3://bucket/a.txt ./ |
|
| ダウンロード(フォルダごと) | aws s3 cp s3://bucket/dir/ ./dir/ --recursive |
sync でも可 |
| S3 から S3 へコピー | aws s3 cp s3://src/a.txt s3://dst/a.txt |
別バケットでも可 |
| 移動(元を消す) | aws s3 mv s3://bucket/a.txt s3://bucket/dir/a.txt |
--recursive で一括 |
| オブジェクトを 1 つ削除 | aws s3 rm s3://bucket/a.txt |
|
| プレフィックス配下を全部削除 | aws s3 rm s3://bucket/dir/ --recursive |
--recursive 必須 |
| 特定拡張子だけ操作 | --exclude "*" --include "*.log" |
順序に注意(後勝ち) |
| 実行前に確認だけする | --dryrun |
(dryrun) 付きで表示 |
| バケットを作る | aws s3 mb s3://bucket |
名前は全世界で一意 |
| バケットを消す | aws s3 rb s3://bucket --force |
--force で中身ごと |
| 期限付き共有 URL を作る | aws s3 presign s3://bucket/a.txt --expires-in 600 |
既定 3600 秒 |
| 静的サイト設定をする | aws s3 website s3://bucket/ --index-document index.html |
|
| 標準入力から直接アップロード | echo hi | aws s3 cp - s3://bucket/a.txt |
- が標準入出力 |
| 内容を画面に出す | aws s3 cp s3://bucket/a.txt - |
ダウンロードせず表示 |
| ストレージクラスを指定 | --storage-class STANDARD_IA |
8 種類から選択 |
| サーバー側暗号化を指定 | --sse AES256 / --sse aws:kms |
|
| 進捗表示を消す(ログ用) | --no-progress / --only-show-errors / --quiet |
CI や cron 向け |
| オブジェクトの詳細を見る | aws s3api head-object --bucket b --key k |
s3 ではなく s3api |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「aws s3コマンド一覧|cp・sync・ls実行例とオプション早見表」
検証環境と前提(本物の AWS なしで同じ手順を再現できます)
この記事の実行結果はすべて、AWS CLI v1 をローカルの S3 互換サーバー moto_server に向けて実行したものです。 認証情報はダミー(testing)で、--endpoint-url で接続先をローカルに向けています。本物の AWS に対して使うときは --endpoint-url ... を外し、aws configure で設定した認証情報とリージョンを使うだけで、コマンドとオプションはそのままです。
# インストール(awscli v1 と、S3 互換サーバーの moto)
pip install "moto[server]" awscli
# S3 互換サーバーをローカルで起動(ポートは自由。ここでは 7580)
moto_server -p 7580 -H 127.0.0.1 &
# ダミーの認証情報とリージョン
export AWS_ACCESS_KEY_ID=testing
export AWS_SECRET_ACCESS_KEY=testing
export AWS_DEFAULT_REGION=ap-northeast-1
# 以降、すべてのコマンドに --endpoint-url を付ける(本物の AWS では不要)
aws --version
aws-cli/1.46.1 Python/3.11.15 Linux/6.18.44-fc-v50 botocore/1.43.62
AWS CLI には v1 と v2 の 2 系統があり、aws s3 の使い方はほぼ同じですが、v2 だけにあるオプションや既定値の違いがあります。 本記事は pip で入る v1(1.46.1、PyPI の最新)で実行し、v2(2.37.3 が最新)との違いは記事の後半にまとめました。以下、見やすさのために --endpoint-url http://127.0.0.1:7580 を $EP と書きます。
EP="--endpoint-url http://127.0.0.1:7580"
検証に使ったローカルのフォルダ構成は次のとおりです(.git/ や logs/ は「除外したいもの」の例として置いています)。
site/
├── index.html
├── notes.txt
├── css/style.css
├── img/logo.png (2,048 バイトのダミー)
├── logs/app.log
└── .git/config
cp・sync・mv の使い分け表(迷ったらここ)
「1 つ・数個を確実に送るなら cp、フォルダを繰り返し反映するなら sync、送った後に元を消したいなら mv」が基本の判断です。 3 つは同じオプション(--exclude、--storage-class、--sse など)をほぼ共有していて、違うのは「何を転送対象にするか」と「元を残すか」です。
| 観点 | cp | sync | mv |
|---|---|---|---|
| 転送対象 | 指定したもの全部(--recursive で配下すべて) |
転送先と比べて「新規」「更新あり」のものだけ | 指定したもの全部 |
| 2 回目の実行 | 同じものをもう一度全部転送する | 変更がなければ何も転送しない | 元がもう無いので何もしない |
| 元ファイル | 残る | 残る | 消える(転送成功後に削除) |
| 転送先だけにあるもの | 残る | 残る(--delete で削除) |
残る |
| 単一ファイル | 可 | 不可(常にディレクトリ単位) | 可 |
--recursive |
複数のとき必要 | 不要(常に再帰) | 複数のとき必要 |
| 向いている場面 | 配布物を 1 回置く、S3 間コピー、標準入出力 | ビルド成果物の反映、バックアップ、ダウンロードの続き | 取り込み済みファイルの退避、リネーム |
判断フローは次のとおりです。
flowchart TD
A[転送したい] --> B{フォルダを繰り返し反映する?}
B -- はい --> C[sync]
C --> D{転送先の余分なものも消したい?}
D -- はい --> E[sync --delete]
D -- いいえ --> C
B -- いいえ --> F{転送後に元を消したい?}
F -- はい --> G[mv]
F -- いいえ --> H[cp]
cp --recursive と sync の違いは、2 回目の実行結果を見るといちばんよくわかります。 同じ site/ を sync で 2 回送ると 2 回目は無出力(転送なし)ですが、cp --recursive は毎回すべて転送します(実行結果は sync のセクションに載せています)。
ls:バケットとオブジェクトの一覧(PRE の意味と末尾スラッシュ)
aws s3 ls は引数なしでバケット一覧、s3://バケット/ を付けるとその階層のオブジェクトと「プレフィックス(PRE)」を表示します。 S3 にフォルダという実体はなく、キーに含まれる / を区切りとして CLI が階層風に見せているだけです。
aws $EP s3 mb s3://rjc-demo-bucket
aws $EP s3 cp site/notes.txt s3://rjc-demo-bucket/ --no-progress
aws $EP s3 cp site/notes.txt s3://rjc-demo-bucket/memo/ --no-progress
aws $EP s3 ls
aws $EP s3 ls s3://rjc-demo-bucket/
aws $EP s3 ls s3://rjc-demo-bucket/memo/
make_bucket: rjc-demo-bucket
upload: site/notes.txt to s3://rjc-demo-bucket/notes.txt
upload: site/notes.txt to s3://rjc-demo-bucket/memo/notes.txt
2026-10-01 07:06:50 rjc-demo-bucket
PRE memo/
2026-10-01 07:10:05 5 notes.txt
2026-10-01 07:10:05 5 notes.txt
末尾のスラッシュの有無で意味が変わります。 s3://bucket/memo(スラッシュなし)は「memo で始まるもの」を探すので、PRE memo/ という行だけが返ります。中身を見たいときは s3://bucket/memo/ のようにスラッシュを付けます。
aws $EP s3 ls s3://rjc-demo-bucket/memo
PRE memo/
配下を全部、人が読みやすい単位で、合計つきで見るには --recursive --human-readable --summarize を組み合わせます。
aws $EP s3 ls s3://rjc-demo-bucket/site/ --recursive --human-readable --summarize
2026-10-01 07:06:54 15 Bytes site/css/style.css
2026-10-01 07:06:54 2.0 KiB site/img/logo.png
2026-10-01 07:06:54 32 Bytes site/index.html
2026-10-01 07:06:54 22 Bytes site/logs/app.log
2026-10-01 07:06:54 24 Bytes site/logs/old.log.gz
2026-10-01 07:06:54 5 Bytes site/notes.txt
Total Objects: 6
Total Size: 2.1 KiB
| ls のオプション | 効果 |
|---|---|
--recursive |
プレフィックス配下をすべて 1 行ずつ表示(PRE は出ない) |
--human-readable |
サイズを Bytes / KiB / MiB で表示 |
--summarize |
末尾にオブジェクト数と合計サイズ |
--page-size 100 |
1 回の API 呼び出しで取る件数(既定 1000)。タイムアウトするとき小さく |
--bucket-name-prefix / --bucket-region |
バケット一覧を名前の先頭・リージョンで絞る(1.46.1 で確認) |
なお、aws s3 ls は存在しないプレフィックスを指定すると何も表示せず、終了コード 1 を返します(実行して確認)。シェルスクリプトで「あるかどうか」を判定する用途にも使えます。
cp:アップロード・ダウンロード・S3 間コピー・標準入出力
aws s3 cp は「ローカル → S3」「S3 → ローカル」「S3 → S3」の 3 方向すべてに使え、出力の先頭語(upload / download / copy)で方向がわかります。 転送先の末尾に / を付けると元のファイル名を保ち、付けなければその名前で保存されます。
aws $EP s3 cp site/notes.txt s3://rjc-demo-bucket/memo/renamed.txt --no-progress
aws $EP s3 cp s3://rjc-demo-bucket/site/index.html ./dl2/index.html --no-progress
aws $EP s3 cp s3://rjc-demo-bucket/site/index.html s3://rjc-demo-bucket/backup/index.html --no-progress
upload: site/notes.txt to s3://rjc-demo-bucket/memo/renamed.txt
download: s3://rjc-demo-bucket/site/index.html to dl2/index.html
copy: s3://rjc-demo-bucket/site/index.html to s3://rjc-demo-bucket/backup/index.html
フォルダごと送るときは --recursive を付けます。 .git/ を除外する例です(--exclude の書き方は後述)。
aws $EP s3 cp site/ s3://rjc-demo-bucket/site/ --recursive --exclude ".git/*" --no-progress
upload: site/logs/app.log to s3://rjc-demo-bucket/site/logs/app.log
upload: site/css/style.css to s3://rjc-demo-bucket/site/css/style.css
upload: site/index.html to s3://rjc-demo-bucket/site/index.html
upload: site/notes.txt to s3://rjc-demo-bucket/site/notes.txt
upload: site/img/logo.png to s3://rjc-demo-bucket/site/img/logo.png
並列に転送されるため、出力の順番は毎回変わります(既定の同時リクエスト数は 10。後述の設定で変更できます)。
- を指定すると標準入力からのアップロード、標準出力へのダウンロードになります。 ログの断片を置く、圧縮しながら送る、内容を確認するだけ、といった場面でファイルを作らずに済みます。
echo 'streamed text' | aws $EP s3 cp - s3://rjc-demo-bucket/stream.txt
aws $EP s3 cp s3://rjc-demo-bucket/stream.txt -
streamed text
(標準入力からのアップロードは成功時に何も表示しません。50 GB を超えるストリームを送るときは --expected-size でおおよそのバイト数を渡します。)
進捗表示について。 端末で実行すると Completed 2.0 KiB/2.1 KiB (88.4 KiB/s) with 5 file(s) remaining のような進捗が同じ行に上書き表示されます。ログに残すと 1 行に何度も混ざって読みにくいので、この記事の例は --no-progress を付けています。CI や cron では --only-show-errors(エラーだけ表示)や --quiet(何も表示しない)も便利です。
sync:差分だけ転送する(1 回目・2 回目・更新後の実行結果)
aws s3 sync は転送元と転送先を比べて「転送先にない」「サイズが違う」「転送元の方が更新時刻が新しい」ファイルだけを転送します。 公式リファレンスの説明どおり、ローカル → S3、S3 → ローカル、S3 → S3 のいずれでもこの 3 条件で判定します。1 回目・2 回目・ファイル変更後の 3 回目を続けて実行した結果です。
aws $EP s3 sync site/ s3://rjc-demo-bucket/sync/ --exclude ".git/*" --no-progress
echo "(何も変えずに 2 回目)"
aws $EP s3 sync site/ s3://rjc-demo-bucket/sync/ --exclude ".git/*" --no-progress
echo "updated" >> site/notes.txt
rm site/logs/app.log
echo "(notes.txt を更新し、logs/app.log を削除して 3 回目)"
aws $EP s3 sync site/ s3://rjc-demo-bucket/sync/ --exclude ".git/*" --no-progress
upload: site/img/logo.png to s3://rjc-demo-bucket/sync/img/logo.png
upload: site/logs/app.log to s3://rjc-demo-bucket/sync/logs/app.log
upload: site/notes.txt to s3://rjc-demo-bucket/sync/notes.txt
upload: site/css/style.css to s3://rjc-demo-bucket/sync/css/style.css
upload: site/index.html to s3://rjc-demo-bucket/sync/index.html
(何も変えずに 2 回目)
(notes.txt を更新し、logs/app.log を削除して 3 回目)
upload: site/notes.txt to s3://rjc-demo-bucket/sync/notes.txt
2 回目は何も転送されず、3 回目は更新した notes.txt だけが転送されました。 ローカルで削除した logs/app.log は S3 に残ったままです。転送先だけにあるものを消して「完全に同じ状態」にするには --delete を付けます。まず --dryrun で何が起こるか確認できます。
aws $EP s3 sync site/ s3://rjc-demo-bucket/sync/ --exclude ".git/*" --delete --dryrun
aws $EP s3 sync site/ s3://rjc-demo-bucket/sync/ --exclude ".git/*" --delete --no-progress
(dryrun) delete: s3://rjc-demo-bucket/sync/logs/app.log
(dryrun) upload: site/notes.txt to s3://rjc-demo-bucket/sync/notes.txt
delete: s3://rjc-demo-bucket/sync/logs/app.log
upload: site/notes.txt to s3://rjc-demo-bucket/sync/notes.txt
(3 回目の後に notes.txt を再度転送しているのは、ローカルの更新時刻が S3 の更新時刻より新しいままだったためです。sync は「サイズが同じでもローカルの方が新しければ転送する」と判定します。)
同じ状態で cp --recursive を実行すると、変更のないファイルも含めて全部が転送されます。 これが cp と sync のいちばん大きな違いです。
aws $EP s3 cp site/ s3://rjc-demo-bucket/sync/ --recursive --exclude ".git/*" --no-progress
upload: site/notes.txt to s3://rjc-demo-bucket/sync/notes.txt
upload: site/img/logo.png to s3://rjc-demo-bucket/sync/img/logo.png
upload: site/css/style.css to s3://rjc-demo-bucket/sync/css/style.css
upload: site/index.html to s3://rjc-demo-bucket/sync/index.html
sync の判定を変えるオプションもあります。 「更新時刻は古いが中身を書き換えた」ファイルで確認しました。index.html を 9 バイトに書き換えたうえで更新時刻を 2020 年に戻しても、サイズが違うので転送対象になります。
| オプション | 判定の変化 | 使う場面 |
|---|---|---|
| (既定) | 転送先にない / サイズが違う / 転送元が新しい、のどれかで転送 | 通常 |
--size-only |
サイズの違いだけで判定(更新時刻は見ない) | ビルドのたびに更新時刻が変わるが中身は同じ、というとき |
--exact-timestamps |
S3 → ローカルで、同サイズなら更新時刻が完全一致のときだけスキップ | S3 側を正として厳密に合わせたいとき |
--delete |
転送先だけにあるものを削除(フィルタで除外したものは削除しない) | 公開フォルダを完全に同期 |
echo "changed!" > site/index.html
touch -d '2020-01-01' site/index.html
aws $EP s3 sync site/ s3://rjc-demo-bucket/sync/ --exclude ".git/*" --dryrun
(dryrun) upload: site/index.html to s3://rjc-demo-bucket/sync/index.html
--exclude と --include は「後に書いた方が勝つ」(順序で結果が変わる実例)
フィルタは「すべてのファイルが対象」という状態から始まり、コマンドラインで後ろに書いたフィルタほど優先されます。 公式リファレンスの「Use of Exclude and Include Filters」にある規則で、--include だけを書いても何も変わりません(--include は「除外されたものを戻す」働きしかないため)。同じ 2 つのフィルタを順序だけ変えて --dryrun で実行した結果です。
# 1) 全部除外してから .html だけ戻す → index.html だけ対象
aws $EP s3 cp site/ s3://rjc-demo-bucket/only-html/ --recursive --exclude "*" --include "*.html" --dryrun
# 2) 順序を逆にすると、最後の --exclude "*" がすべてを除外 → 何も対象にならない
aws $EP s3 cp site/ s3://rjc-demo-bucket/only-html/ --recursive --include "*.html" --exclude "*" --dryrun
# 3) --include だけ → 既定で全部対象なので、全部が対象のまま
aws $EP s3 cp site/ s3://rjc-demo-bucket/only-html/ --recursive --include "*.html" --dryrun
(dryrun) upload: site/index.html to s3://rjc-demo-bucket/only-html/index.html
(2 の出力:なし)
(dryrun) upload: site/.git/config to s3://rjc-demo-bucket/only-html/.git/config
(dryrun) upload: site/css/style.css to s3://rjc-demo-bucket/only-html/css/style.css
(dryrun) upload: site/img/logo.png to s3://rjc-demo-bucket/only-html/img/logo.png
(dryrun) upload: site/index.html to s3://rjc-demo-bucket/only-html/index.html
(dryrun) upload: site/logs/app.log to s3://rjc-demo-bucket/only-html/logs/app.log
(dryrun) upload: site/logs/old.log.gz to s3://rjc-demo-bucket/only-html/logs/old.log.gz
(dryrun) upload: site/notes.txt to s3://rjc-demo-bucket/only-html/notes.txt
パターンの規則と、よく使う組み合わせを表にまとめます。 パターンは転送元ディレクトリからの相対パスに対して評価されるので、logs/* のようにディレクトリ名から書きます(* は / もまたいで一致します)。シェルに展開されないよう、パターンは必ず引用符で囲みます。
| 書き方 | 意味 |
|---|---|
* |
すべてに一致(/ も含む) |
? |
任意の 1 文字 |
[abc] / [!abc] |
括弧内のどれか 1 文字 / それ以外の 1 文字 |
--exclude "*.jpg" |
jpg を除外して他は全部 |
--exclude "*" --include "*.html" --include "*.css" |
html と css だけ |
--exclude "logs/*" --exclude ".git/*" |
2 つのディレクトリを除外 |
--exclude "*" --include "2026-10-*" |
特定の日付で始まるものだけ |
aws $EP s3 cp site/ s3://rjc-demo-bucket/web/ --recursive --exclude "*" --include "*.html" --include "*.css" --dryrun
aws $EP s3 cp site/ s3://rjc-demo-bucket/nolog/ --recursive --exclude "logs/*" --exclude ".git/*" --dryrun
(dryrun) upload: site/css/style.css to s3://rjc-demo-bucket/web/css/style.css
(dryrun) upload: site/index.html to s3://rjc-demo-bucket/web/index.html
(dryrun) upload: site/css/style.css to s3://rjc-demo-bucket/nolog/css/style.css
(dryrun) upload: site/img/logo.png to s3://rjc-demo-bucket/nolog/img/logo.png
(dryrun) upload: site/index.html to s3://rjc-demo-bucket/nolog/index.html
(dryrun) upload: site/notes.txt to s3://rjc-demo-bucket/nolog/notes.txt
なお、パス引数そのものにワイルドカードは使えません(aws s3 cp s3://bucket/*.log ./ は動きません)。「特定のものだけ」はすべて --exclude / --include で表現します。sync --delete と組み合わせたとき、フィルタで除外したファイルは削除の対象にもなりません。
mv・rm:移動と削除(rm は --recursive を忘れると消えません)
aws s3 mv は cp と同じ書き方で、転送が成功した後に元を削除します。 S3 内のリネームや「取り込み済みフォルダへの退避」に使います。
aws $EP s3 mv s3://rjc-demo-bucket/notes.txt s3://rjc-demo-bucket/moved/notes.txt --no-progress
aws $EP s3 mv s3://rjc-demo-bucket/memo/ s3://rjc-demo-bucket/moved/memo/ --recursive --no-progress
move: s3://rjc-demo-bucket/notes.txt to s3://rjc-demo-bucket/moved/notes.txt
move: s3://rjc-demo-bucket/memo/renamed.txt to s3://rjc-demo-bucket/moved/memo/renamed.txt
move: s3://rjc-demo-bucket/memo/notes.txt to s3://rjc-demo-bucket/moved/memo/notes.txt
aws s3 rm でプレフィックス(フォルダ)を消すときは --recursive が必須です。 --recursive なしで s3://bucket/site/logs/ を指定すると、CLI は「site/logs/ という名前の 1 オブジェクト」を削除しようとします。S3 の削除は存在しないキーでも成功扱いなので delete: と表示されますが、配下のファイルは残ったままです。実行して確かめました。
aws $EP s3 rm s3://rjc-demo-bucket/site/logs/
aws $EP s3 ls s3://rjc-demo-bucket/site/logs/
aws $EP s3 rm s3://rjc-demo-bucket/site/logs/ --recursive
aws $EP s3 ls s3://rjc-demo-bucket/site/logs/
delete: s3://rjc-demo-bucket/site/logs/
2026-10-01 07:10:08 22 app.log
delete: s3://rjc-demo-bucket/site/logs/app.log
(最後の ls は何も表示せず終了コード 1。配下が空になったことがわかります。)
削除の前には --dryrun、拡張子を絞るなら --exclude "*" --include "*.log" です。 rm でもフィルタの順序規則は同じです。
aws $EP s3 rm s3://rjc-demo-bucket/site/ --recursive --dryrun
aws $EP s3 rm s3://rjc-demo-bucket/site/ --recursive --exclude "*" --include "*.log"
(dryrun) delete: s3://rjc-demo-bucket/site/css/style.css
(dryrun) delete: s3://rjc-demo-bucket/site/img/logo.png
(dryrun) delete: s3://rjc-demo-bucket/site/index.html
(dryrun) delete: s3://rjc-demo-bucket/site/logs/app.log
(dryrun) delete: s3://rjc-demo-bucket/site/logs/old.log.gz
(dryrun) delete: s3://rjc-demo-bucket/site/notes.txt
delete: s3://rjc-demo-bucket/site/logs/app.log
バージョニングが有効なバケットでは、rm は「削除マーカー」を置くだけで過去バージョンは残ります。古いバージョンまで消すには aws s3api delete-object --version-id ... を使います(rb --force も同じ理由でバージョン付きオブジェクトは消せません)。
mb・rb・presign・website:バケット作成・削除・署名付き URL・静的サイト
バケットは mb で作り、rb で消します。中身が残っていると rb は BucketNotEmpty で止まるので、--force を付けると中身を消してからバケットを削除します。
aws $EP s3 rb s3://rjc-demo-archive
aws $EP s3 rb s3://rjc-demo-archive --force
remove_bucket failed: s3://rjc-demo-archive An error occurred (BucketNotEmpty) when calling the DeleteBucket operation: The bucket you tried to delete is not empty
delete: s3://rjc-demo-archive/backup/index.html
remove_bucket: rjc-demo-archive
presign は、認証情報を持たない相手にも一定時間だけダウンロードを許す URL を作ります。 既定の有効期限は 3600 秒(1 時間)で、--expires-in 秒で変更できます。URL には署名(X-Amz-Signature)と期限(X-Amz-Expires)が含まれます。生成した URL を curl で取得できることも確認しました。
aws $EP s3 presign s3://rjc-demo-bucket/site/index.html --expires-in 600
curl -s "$(aws $EP s3 presign s3://rjc-demo-bucket/site/index.html --expires-in 600)"
http://127.0.0.1:7580/rjc-demo-bucket/site/index.html?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=testing%2F20260930%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Date=20260930T221018Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=8a70747e4ba66040ae1d88a4f9fc1d9e92aa19770cfc3bed0f8ee08a64a3c378
<html><body>hello</body></html>
本物の S3 ではホスト部分が https://rjc-demo-bucket.s3.ap-northeast-1.amazonaws.com/... になります。署名 v4 の URL は最長 7 日(604800 秒)までで、v2 のリファレンスにも「Maximum is 604800 seconds」と明記されています。ローカル検証では aws configure set default.s3.signature_version s3v4 を設定して v4 形式にしました(本物の AWS では既定で v4 です)。
website はバケットの静的ウェブサイト設定(インデックス文書とエラー文書)を入れるコマンドです。 設定内容は s3api get-bucket-website で確認できます。
aws $EP s3 website s3://rjc-demo-bucket/ --index-document index.html --error-document error.html
aws $EP s3api get-bucket-website --bucket rjc-demo-bucket
{
"IndexDocument": {
"Suffix": "index.html"
},
"ErrorDocument": {
"Key": "error.html"
}
}
実際に公開するには、これに加えてブロックパブリックアクセスの設定とバケットポリシー(s3:GetObject の許可)が必要です。バケットポリシーの入れ方は s3api のセクションに載せています。
オプション早見表(目的別)
cp・sync・mv に共通する主なオプションを目的別にまとめました。 「ストレージクラス」「暗号化」「メタデータ」は 1.46.1 で実行して、s3api head-object で設定が反映されたことを確認しています。
| 目的 | オプション | 補足 |
|---|---|---|
| 実行前の確認 | --dryrun |
転送・削除せず (dryrun) 付きで表示 |
| 配下すべてを対象に | --recursive |
cp・mv・rm で必要 |
| 転送先の余分を削除 | --delete |
sync のみ |
| 対象を絞る | --exclude / --include |
後に書いた方が優先 |
| ストレージクラス | --storage-class STANDARD_IA |
値は下の表 |
| サーバー側暗号化 | --sse AES256 / --sse aws:kms --sse-kms-key-id <キーID> |
値を省略すると AES256 |
| Content-Type を指定 | --content-type text/plain |
既定は拡張子から推測(--no-guess-mime-type で無効化) |
| キャッシュ制御 | --cache-control "max-age=3600" |
CDN 配信の静的ファイルで |
| ユーザー定義メタデータ | --metadata "owner=rjc,env=dev" |
x-amz-meta-* として保存 |
| ACL | --acl bucket-owner-full-control など |
s3:PutObjectAcl 権限が必要 |
| 進捗を消す | --no-progress / --only-show-errors / --quiet |
ログ・CI 向け |
| シンボリックリンク | --follow-symlinks(既定) / --no-follow-symlinks |
ローカル → S3 のみ |
| 転送元リージョン | --source-region ap-northeast-1 |
S3 間コピーでリージョンが違うとき |
| 1 ページの件数 | --page-size 500 |
一覧でタイムアウトするとき小さく |
| 大文字小文字だけ違うキー | --case-conflict error|warn|skip|ignore |
大文字小文字を区別しない OS へダウンロードするとき |
| チェックサム | --checksum-algorithm CRC32 など / --checksum-mode ENABLED |
1.37.0 以降は既定で CRC32 を計算 |
| 認証なしで公開バケットへ | --no-sign-request |
認証情報を読み込まない |
| プロファイル・リージョン | --profile dev / --region ap-northeast-1 |
全コマンド共通 |
ストレージクラスは 8 種類から選び、綴りを間違えると CLI が候補を表示して止まります(実行結果)。
aws $EP s3 cp site/img/logo.png s3://rjc-demo-bucket/opt/logo-ia.png --storage-class STANDARD_IA --no-progress
aws $EP s3api head-object --bucket rjc-demo-bucket --key opt/logo-ia.png
aws $EP s3 cp site/img/logo.png s3://rjc-demo-bucket/opt/logo-bad.png --storage-class COLD
upload: site/img/logo.png to s3://rjc-demo-bucket/opt/logo-ia.png
{
"AcceptRanges": "bytes",
"LastModified": "Wed, 30 Sep 2026 22:07:04 GMT",
"ContentLength": 2048,
"ETag": "\"8041213b524ba0aa4ee0300ec9f44073\"",
"ContentType": "image/png",
"Metadata": {},
"StorageClass": "STANDARD_IA"
}
aws: error: argument --storage-class: Invalid choice, valid choices are:
STANDARD | REDUCED_REDUNDANCY
STANDARD_IA | ONEZONE_IA
INTELLIGENT_TIERING | GLACIER
DEEP_ARCHIVE | GLACIER_IR
| ストレージクラス | 向いているデータ |
|---|---|
| STANDARD(既定) | 頻繁に読むデータ |
| INTELLIGENT_TIERING | アクセス頻度が読めないデータ(自動で階層移動) |
| STANDARD_IA / ONEZONE_IA | 月に数回程度しか読まないが、すぐ取り出したいデータ |
| GLACIER_IR | 四半期に 1 回程度、ミリ秒で取り出したいアーカイブ |
| GLACIER / DEEP_ARCHIVE | 長期保管(取り出しに数分〜数時間) |
| REDUCED_REDUNDANCY | 旧来のクラス(新規では STANDARD を推奨) |
暗号化とメタデータも同じように指定し、head-object の --query で確認できます。
aws $EP s3 cp site/notes.txt s3://rjc-demo-bucket/opt/notes-sse.txt --sse AES256 --no-progress
aws $EP s3api head-object --bucket rjc-demo-bucket --key opt/notes-sse.txt \
--query "{SSE:ServerSideEncryption,Size:ContentLength,Type:ContentType}"
aws $EP s3 cp site/notes.txt s3://rjc-demo-bucket/opt/notes-meta.txt \
--content-type text/plain --cache-control "max-age=3600" --metadata "owner=rjc,env=dev" --no-progress
aws $EP s3api head-object --bucket rjc-demo-bucket --key opt/notes-meta.txt \
--query "{Type:ContentType,Cache:CacheControl,Meta:Metadata}"
{
"SSE": "AES256",
"Size": 13,
"Type": "text/plain"
}
{
"Type": "text/plain",
"Cache": "max-age=3600",
"Meta": {
"owner": "rjc",
"env": "dev"
}
}
aws s3 と aws s3api の違い(主要コマンド対応表)
aws s3 は複数ファイルの転送や差分同期など「人が使いやすい」高レベルコマンド、aws s3api は S3 の API を 1 対 1 で呼ぶ低レベルコマンドです。 バケットの設定(ポリシー、バージョニング、暗号化、パブリックアクセスブロック)やオブジェクトの詳細取得(head-object)は aws s3 にないので、s3api を使います。出力は JSON で、--query(JMESPath)と --output table|text で加工できます。
| やりたいこと | aws s3 | aws s3api |
|---|---|---|
| 一覧 | ls |
list-objects-v2 --bucket b --prefix p/ |
| アップロード | cp |
put-object --bucket b --key k --body file |
| ダウンロード | cp |
get-object --bucket b --key k 出力ファイル |
| メタデータ・サイズ・クラス確認 | なし | head-object --bucket b --key k |
| バケットの存在・リージョン | ls(存在のみ) |
head-bucket / get-bucket-location |
| 複数削除 | rm --recursive |
delete-objects --delete Objects=[{Key=a},{Key=b}] |
| バケットポリシー | なし | put-bucket-policy --policy file://policy.json / get-bucket-policy |
| バージョニング | なし | put-bucket-versioning --versioning-configuration Status=Enabled |
| 既定の暗号化 | なし | put-bucket-encryption / get-bucket-encryption |
| パブリックアクセスブロック | なし | put-public-access-block / get-public-access-block |
| 過去バージョン一覧 | なし | list-object-versions |
| 静的サイト設定 | website |
put-bucket-website / get-bucket-website |
| 署名付き URL | presign |
なし(SDK の generate_presigned_url) |
ls と list-objects-v2 の違いを実行結果で比べます。 list-objects-v2 は 1 回の呼び出しで最大 1000 件、--max-keys で件数を絞ると IsTruncated と NextContinuationToken が返り、続きは --starting-token で取ります(aws s3 ls はこのページングを自動でやってくれています)。
aws $EP s3api list-objects-v2 --bucket rjc-demo-bucket --prefix site/ --max-keys 2
{
"IsTruncated": true,
"Contents": [
{
"Key": "site/css/style.css",
"LastModified": "2026-09-30T22:06:54.000Z",
"ETag": "\"3c7253c0b17971959285c18f6eea6509\"",
"ChecksumAlgorithm": [
"CRC32"
],
"Size": 15,
"StorageClass": "STANDARD"
},
{
"Key": "site/img/logo.png",
"LastModified": "2026-09-30T22:06:54.000Z",
"ETag": "\"8041213b524ba0aa4ee0300ec9f44073\"",
"ChecksumAlgorithm": [
"CRC32"
],
"Size": 2048,
"StorageClass": "STANDARD"
}
],
"Name": "rjc-demo-bucket",
"Prefix": "site/",
"MaxKeys": 2,
"EncodingType": "url",
"KeyCount": 2,
"NextContinuationToken": "71cc9846684df4d5498962d05d21373f"
}
--query と --output table を使うと、必要な列だけを表にできます。 「100 バイトより大きいものだけ」のような条件も JMESPath で書けます。
aws $EP s3api list-objects-v2 --bucket rjc-demo-bucket --prefix site/ \
--query "Contents[].[Key,Size,StorageClass]" --output table
aws $EP s3api list-objects-v2 --bucket rjc-demo-bucket \
--query "Contents[?Size > \`100\`].[Key,Size]" --output text
----------------------------------------------
| ListObjectsV2 |
+-----------------------+-------+------------+
| site/css/style.css | 15 | STANDARD |
| site/img/logo.png | 2048 | STANDARD |
| site/index.html | 32 | STANDARD |
| site/logs/old.log.gz | 24 | STANDARD |
| site/notes.txt | 5 | STANDARD |
+-----------------------+-------+------------+
site/img/logo.png 2048
sync/img/logo.png 2048
バケットポリシー・バージョニング・既定暗号化・パブリックアクセスブロックは s3api で設定します。 ポリシーは JSON ファイルを file:// で渡します(例は site/ 配下の読み取りだけを許可するもの)。
cat > policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicReadOfSite",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::rjc-demo-bucket/site/*"
}
]
}
EOF
aws $EP s3api put-bucket-policy --bucket rjc-demo-bucket --policy file://policy.json
aws $EP s3api get-bucket-policy --bucket rjc-demo-bucket --query Policy --output text
aws $EP s3api put-bucket-versioning --bucket rjc-demo-bucket --versioning-configuration Status=Enabled
aws $EP s3api get-bucket-versioning --bucket rjc-demo-bucket
aws $EP s3api put-bucket-encryption --bucket rjc-demo-bucket \
--server-side-encryption-configuration '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
aws $EP s3api put-public-access-block --bucket rjc-demo-bucket \
--public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
aws $EP s3api get-public-access-block --bucket rjc-demo-bucket
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPublicReadOfSite",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::rjc-demo-bucket/site/*"
}
]
}
{
"Status": "Enabled"
}
{
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": true,
"IgnorePublicAcls": true,
"BlockPublicPolicy": true,
"RestrictPublicBuckets": true
}
}
(put-* 系は成功時に何も表示しません。バージョニングを有効にした後の delete-object は "DeleteMarker": true を返し、過去バージョンは list-object-versions に残ります。)
よくあるエラー文と対処(実際の出力)
エラーは「認証情報がない」「権限がない」「対象がない」「引数の形が違う」の 4 種類にほぼ分類でき、メッセージの括弧内(AccessDenied など)を見れば原因が絞れます。 権限まわりのエラーは、moto_server を IAM 検証モードで起動し、s3:ListBucket しか許可していない IAM ユーザーのアクセスキーで実行して再現しました(INITIAL_NO_AUTH_ACTION_COUNT=5 moto_server -p 7581 で起動し、最初の 5 リクエストでユーザー・ポリシー・バケット・アクセスキーを作成)。
| エラー文(抜粋) | 意味 | 対処 |
|---|---|---|
Unable to locate credentials. You can configure credentials by running "aws configure". |
認証情報がどこにも設定されていない | aws configure、環境変数、--profile、IAM ロールのいずれかを設定 |
An error occurred (InvalidAccessKeyId) when calling the ListObjectsV2 operation: The AWS Access Key Id you provided does not exist in our records. |
アクセスキー ID が存在しない(削除済み・別アカウント・貼り間違い) | キーを再確認。aws sts get-caller-identity で誰として動いているか確認 |
An error occurred (SignatureDoesNotMatch) when calling the ListObjectsV2 operation: The request signature we calculated does not match the signature you provided. Check your key and signing method. |
シークレットキーが違う、または時計が大きくずれている | シークレットを再設定。OS の時刻同期を確認 |
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied |
権限がない(IAM ポリシー / バケットポリシー / ブロックパブリックアクセス) | 必要なアクション(s3:ListAllMyBuckets など)をポリシーに追加 |
upload failed: ... An error occurred (AccessDenied) when calling the PutObject operation: Access Denied |
s3:PutObject が許可されていない(KMS 暗号化バケットなら kms:GenerateDataKey も必要) |
ポリシーの Action と Resource(arn:aws:s3:::bucket/*)を確認 |
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden |
aws s3 cp のダウンロードで s3:GetObject がない(HeadObject は本文なしで 403 だけ返る) |
s3:GetObject を許可。詳細は s3api get-object で確認すると AccessDenied と出る |
fatal error: An error occurred (404) when calling the HeadObject operation: Not Found |
ダウンロード元のキーが存在しない(本物の S3 での文言) | キー名・プレフィックスを ls で確認 |
An error occurred (NoSuchBucket) when calling the ListObjectsV2 operation: The specified bucket does not exist |
バケット名が違う、または別リージョン・別アカウント | バケット名を aws s3 ls で確認 |
remove_bucket failed: ... (BucketNotEmpty) ... The bucket you tried to delete is not empty |
中身が残っている | rb --force、バージョン付きは delete-object --version-id |
The user-provided path notfound.txt does not exist. |
ローカル側のパスが違う | パスを確認 |
usage: aws s3 cp <LocalPath> <S3Uri> or ... Error: Invalid argument type |
s3:// を付け忘れた |
S3 側のパスは必ず s3:// から書く |
実際の出力です(上から順に、認証情報なし、存在しないキー ID、誤ったシークレット、権限不足 3 種。$EP2 は IAM 検証モードで起動した 7581 番ポートの moto_server です)。
EP2="--endpoint-url http://127.0.0.1:7581"
AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= aws $EP s3 ls
AWS_ACCESS_KEY_ID=AKIANOTEXIST12345678 aws $EP2 s3api list-objects-v2 --bucket rjc-demo-bucket --query 'Contents[].Key'
AWS_SECRET_ACCESS_KEY=wrongsecret aws $EP2 s3api list-objects-v2 --bucket rjc-demo-bucket --query 'Contents[].Key'
aws $EP2 s3 ls # reader ユーザー(ListBucket のみ)
aws $EP2 s3 cp site/notes.txt s3://rjc-demo-bucket/notes.txt --no-progress
aws $EP2 s3 cp s3://rjc-demo-bucket/index.html ./dl-index.html
Unable to locate credentials. You can configure credentials by running "aws configure".
An error occurred (InvalidAccessKeyId) when calling the ListObjectsV2 operation: The AWS Access Key Id you provided does not exist in our records.
An error occurred (SignatureDoesNotMatch) when calling the ListObjectsV2 operation: The request signature we calculated does not match the signature you provided. Check your key and signing method.
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
upload failed: site/notes.txt to s3://rjc-demo-bucket/notes.txt An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
存在しないバケット・キーの出力です。 存在しないキーを cp したときの文言は、moto では Key "nothing.txt" does not exist、本物の S3 では Not Found と表示されます(head-object は moto でも Not Found)。
aws $EP s3 ls s3://no-such-bucket-rjc-xyz
aws $EP s3 cp s3://rjc-demo-bucket/nothing.txt ./
aws $EP s3api head-object --bucket rjc-demo-bucket --key nothing.txt
An error occurred (NoSuchBucket) when calling the ListObjectsV2 operation: The specified bucket does not exist
fatal error: An error occurred (404) when calling the HeadObject operation: Key "nothing.txt" does not exist
An error occurred (404) when calling the HeadObject operation: Not Found
終了コードも覚えておくと、スクリプトでの分岐に使えます。 1.46.1 で確認した値です。
| 状況 | 終了コード |
|---|---|
| 成功 | 0 |
ls で該当なし、cp/rm の一部失敗(upload failed、fatal error) |
1 |
| 引数の誤り(不正な選択肢、未知のオプション) | 2 |
| API エラー(AccessDenied、NoSuchBucket など)、認証情報なし | 255 |
大容量転送の設定(aws configure set default.s3.*)
大きなファイルや大量のファイルを扱うときは、CLI の S3 転送設定(同時リクエスト数・マルチパートのしきい値・帯域上限)を aws configure set で調整できます。 設定は ~/.aws/config の s3 セクションに書かれ、cp・sync・mv の高レベルコマンドだけに効きます(s3api には効きません)。既定値と意味は公式の「AWS CLI S3 Configuration」で確認しました。
| 設定 | 既定値 | 意味 | 増減の目安 |
|---|---|---|---|
max_concurrent_requests |
10 | 同時に投げるリクエスト数 | 回線が太く CPU に余裕があれば 20〜50。共有回線で他に影響が出るなら減らす |
max_queue_size |
1000 | 転送待ちタスクの上限 | 数万ファイルを sync するとき 10000 程度に |
multipart_threshold |
8MB | このサイズ以上をマルチパート転送に切り替える | 大きいファイルが多ければ 64MB など |
multipart_chunksize |
8MB | マルチパートの 1 パートのサイズ(最小 5MB) | 16MB〜64MB。パート数は最大 10,000 |
max_bandwidth |
なし | 帯域の上限(50MB/s、300KB/s、10Mb/s) |
業務時間中の回線を圧迫したくないとき |
use_accelerate_endpoint |
false | Transfer Acceleration を使う(バケット側で有効化が必要) | 遠いリージョンへ大量転送するとき |
addressing_style |
auto | virtual(バケット名をホストに)/ path |
S3 互換サービスで path を求められることがある |
aws configure set default.s3.max_concurrent_requests 20
aws configure set default.s3.max_queue_size 10000
aws configure set default.s3.multipart_threshold 64MB
aws configure set default.s3.multipart_chunksize 16MB
aws configure set default.s3.max_bandwidth 50MB/s
cat ~/.aws/config
[default]
s3 =
max_concurrent_requests = 20
max_queue_size = 10000
multipart_threshold = 64MB
multipart_chunksize = 16MB
max_bandwidth = 50MB/s
(検証では AWS_CONFIG_FILE を作業フォルダ内のファイルに向けて実行しました。プロファイルごとに変えるなら default の部分を profile.dev のようにします。)
大容量転送のチェックリストです。
| 確認すること | 理由 |
|---|---|
まず --dryrun で件数と対象を確認 |
数万件の転送は途中で止めにくい |
sync を使う |
途中で切れても再実行すれば続きから転送される |
--only-show-errors でログを絞る |
進捗行が大量に出るとログが読めない |
multipart_chunksize × 10,000 がファイルサイズを超えるか |
5 TB のファイルは 1 パート 512 MB 以上が必要 |
| 同じリージョン内で転送する | リージョン間はデータ転送料金と時間がかかる |
--storage-class を最初から指定 |
後からクラスを変えると追加のリクエストが要る |
AWS CLI v1 と v2 の違い(aws s3 まわり)
aws s3 のコマンド体系は v1 と v2 で同じですが、v2 だけにあるオプションと既定値の違いがあります。 公式の「Breaking changes – Migrating from AWS CLI version 1 to version 2」と各リファレンスで確認した内容です。1.46.1 で v2 のオプションを指定すると Unknown options: --no-overwrite と表示されることも確認しました。
| 項目 | v1(1.46.1 で確認) | v2(2.37.3) |
|---|---|---|
| 入手方法 | pip install awscli(Python が必要) |
公式インストーラー(Python 同梱) |
--no-overwrite(転送先にあるファイルを上書きしない) |
なし(Unknown options) | あり |
--copy-props(S3 間コピーでタグ・メタデータをどこまで写すか) |
なし | あり(既定 default でタグも写す。API 呼び出しが増える) |
| 転送時の既定チェックサム | CRC32(1.37.0 以降) | CRC64NVME(2.23.0 以降) |
| us-east-1 の既定エンドポイント | グローバル s3.amazonaws.com |
リージョナル s3.us-east-1.amazonaws.com |
| 署名方式 | v4 が既定(接続先によっては旧形式の署名になることがあり、aws configure set default.s3.signature_version s3v4 で固定できる) |
v4 のみ(presign は最長 7 日) |
s3api の出力ページャー |
なし | 既定で less が起動(AWS_PAGER="" や --no-cli-pager で無効化) |
| タイムスタンプの出力形式 | API の形式そのまま | ISO 8601 に統一(cli_timestamp_format = wire で戻せる) |
| 引数エラー時の表示 | 「v2 が推奨です」という Note が先頭に出る | なし |
--v2-debug |
v2 に移行したときに影響する変更を警告表示 | なし |
どちらを使うかは、既存のスクリプトと実行環境に合わせるのが現実的です。新しく入れるなら v2、pip で管理したい・Python 環境に同梱したいなら v1、という選び方になります。
よくある質問
Q. aws s3 cp と aws s3 sync はどちらを使えばよいですか?
A. 1 つ〜数個のファイルを置く、S3 間でコピーする、標準入出力を使うなら cp、フォルダを繰り返し反映するなら sync です。sync は 2 回目以降に差分だけを転送し、途中で切れても再実行で続きから転送できます。転送先だけにある余分なものも消したいときは sync --delete を、先に --dryrun で確認してから使います。
Q. --include "*.log" を付けたのに全部転送されてしまいます。
A. 既定ではすべてのファイルが対象で、--include は「除外されたものを戻す」働きしかありません。特定の拡張子だけにするには --exclude "*" --include "*.log" の順で書きます。逆順(--include の後に --exclude "*")にすると、後に書いた --exclude "*" が勝って何も転送されません。
Q. aws s3 rm s3://bucket/dir/ を実行したのにファイルが残っています。
A. --recursive なしの rm は「dir/ という名前の 1 オブジェクト」を消す動作で、配下のファイルは対象になりません。aws s3 rm s3://bucket/dir/ --recursive と書きます。バージョニングが有効なバケットでは削除マーカーが置かれるだけで、過去バージョンは s3api delete-object --version-id で消します。
Q. AccessDenied が出たとき、何から確認すればよいですか?
A. まず aws sts get-caller-identity で「誰として」実行しているかを確認し、次にエラー文の operation(PutObject、ListBuckets など)に対応する IAM のアクション(s3:PutObject、s3:ListAllMyBuckets など)と Resource(バケットは arn:aws:s3:::bucket、オブジェクトは arn:aws:s3:::bucket/*)がポリシーにあるかを見ます。IAM で許可されていてもバケットポリシーの Deny やブロックパブリックアクセス、KMS キーの権限で拒否されることがあります。aws s3 cp のダウンロードでは 403 Forbidden(HeadObject)と表示されるので、s3api get-object で試すと AccessDenied と詳しく出ます。
まとめ
aws s3は cp・sync・mv・rm・ls・mb・rb・presign・website の 9 コマンドで、--recursiveが要るのは cp・mv・rm だけです。- cp は毎回全部、sync は差分だけ、mv は転送後に元を削除。フォルダの繰り返し反映は sync、余分を消すなら
sync --delete(先に--dryrun)。 --exclude/--includeは後に書いた方が優先。特定拡張子だけなら--exclude "*" --include "*.ext"の順。rmでフォルダを消すには--recursiveが必須。なしだとdelete:と表示されても配下は残ります。--storage-class・--sse・--content-type・--metadataは cp/sync/mv 共通で、反映はs3api head-objectで確認できます。- バケットの設定(ポリシー・バージョニング・暗号化・パブリックアクセスブロック)と詳細取得は
aws s3api。出力は--queryと--output tableで整形。 - エラーは括弧内の名前で分類(InvalidAccessKeyId は ID、SignatureDoesNotMatch はシークレット、AccessDenied は権限、NoSuchBucket は名前)。
- 大容量転送は
aws configure set default.s3.max_concurrent_requestsなどで調整。v1 と v2 の違いは--no-overwrite・--copy-props・既定チェックサム・ページャー。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「aws s3コマンド一覧|cp・sync・ls実行例とオプション早見表」
株式会社RJCでは、こうしたクラウドの CLI 操作を、実際に手を動かして出力を確かめながらプロジェクトの中で仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。