[AWS] S3 CLI 파일 대량 복사: * 대신 --recursive, --exclude, --include 사용하기!
AWS S3는 뛰어난 스토리지 서비스지만, 다수의 파일을 CLI로 한 번에 옮기려고 할 때 쉘의 와일드카드(*
)가 생각처럼 동작하지 않아 당황하는 경우가 종종 있습니다. 예를 들어 aws s3 cp ./my_files/* s3://my-bucket/
과 같은 명령어가 모든 파일을 선택해주길 기대하지만, S3 CLI는 이런 방식보다는 자체적인 옵션을 통해 파일 및 폴더를 재귀적으로 처리하도록 설계되어 있습니다.
이 글에서는 AWS S3 CLI의 강력한 옵션인 --recursive
, --exclude
, --include
를 활용하여 여러 객체(파일 및 폴더)를 효율적으로 복사하는 방법을 다양한 예시와 함께 알아보겠습니다.
1. 기본: --recursive
옵션으로 전체 복사하기
--recursive
옵션은 지정된 디렉토리(S3에서는 "prefix") 하위의 모든 파일과 폴더를 재귀적으로 탐색하여 명령을 수행합니다.
1.1. 로컬의 모든 파일을 S3 버킷으로 업로드
로컬 현재 디렉토리(./
)의 모든 내용을 S3 버킷의 특정 경로 (또는 루트)로 업로드합니다. 로컬의 폴더 구조는 S3 내에서도 동일하게 유지됩니다.
aws s3 cp ./ s3://your-bucket-name/destination-prefix/ --recursive
./
: 로컬의 현재 디렉토리를 의미합니다. 특정 로컬 폴더를 지정할 수도 있습니다 (예:aws s3 cp ./my_data s3://...
).s3://your-bucket-name/destination-prefix/
: 대상 S3 버킷 이름과 업로드될 경로(prefix)입니다. 경로 끝에/
를 붙여 폴더임을 명시하는 것이 좋습니다.- 참고: 만약 로컬에 빈 폴더가 있다면, 해당 빈 폴더는 S3로 업로드되지 않습니다. S3는 객체 기반 스토리지이므로, 내용이 없는 "폴더" 자체는 별도로 생성되지 않습니다.
1.2. S3 버킷의 모든 객체를 로컬로 다운로드
S3 버킷 (또는 특정 prefix)의 모든 객체를 로컬 시스템의 현재 디렉토리로 다운로드합니다. S3의 "폴더" 구조가 로컬에도 그대로 유지됩니다.
aws s3 cp s3://your-bucket-name/source-prefix/ ./local_destination_folder/ --recursive
s3://your-bucket-name/source-prefix/
: 다운로드할 S3 버킷 및 소스 경로입니다. 버킷 전체를 받고 싶다면s3://your-bucket-name/
으로 지정합니다../local_destination_folder/
: 로컬에 다운로드될 대상 폴더입니다.
(팁: S3에서 "폴더"는 실제로는 객체 키(이름)의 일부입니다. 예를 들어, photos/image.jpg
라는 객체는 photos/
라는 "폴더" 안에 image.jpg
파일이 있는 것처럼 보이지만, 실제로는 /
문자를 포함하는 하나의 키일 뿐입니다. 하지만 CLI는 이를 폴더 구조처럼 편리하게 다룰 수 있게 해줍니다.)
2. 고급: --exclude
와 --include
로 조건부 복사하기
때로는 특정 조건에 맞는 파일만 복사하거나, 특정 파일들을 제외하고 복사하고 싶을 때가 있습니다. 이때 --exclude
(제외)와 --include
(포함) 옵션을 사용합니다.
매우 중요한 점: --exclude
와 --include
옵션은 명령어에 나타난 순서대로 적용됩니다. 즉, 어떤 필터가 먼저 적용되느냐에 따라 결과가 완전히 달라질 수 있습니다.
2.1. --exclude
: 특정 파일/패턴 제외하기
--exclude
옵션은 지정된 패턴과 일치하는 파일을 복사 대상에서 제외합니다.
예시 1: 모든 .log
파일 제외하고 업로드
aws s3 cp ./my_project/ s3://your-bucket-name/project_backup/ --recursive --exclude "*.log"
위 명령어는 my_project
폴더의 내용 중 확장자가 .log
인 파일을 제외한 모든 것을 S3로 복사합니다.
예시 2: 특정 폴더(tmp/
) 제외하고 업로드
aws s3 cp ./ s3://your-bucket-name/full_backup/ --recursive --exclude "tmp/*"
tmp
폴더와 그 안의 모든 내용을 제외하고 업로드합니다. *
는 해당 폴더 내 모든 파일을 의미합니다.
2.2. --include
: 특정 파일/패턴만 포함하기 (주의!)
--include
옵션은 지정된 패턴과 일치하는 파일만 복사 대상에 포함합니다. 하지만 단독으로 사용될 때의 동작 방식에 주의해야 합니다. 기본적으로 모든 파일이 고려 대상이므로, --include "*.txt"
만 사용하면 모든 파일이 고려된 후 .txt
파일이 "포함"되지만, 다른 파일이 "제외"되지는 않아 사실상 모든 파일이 복사될 수 있습니다.
따라서 특정 파일만 포함시키고 싶을 때는 먼저 모든 파일을 제외(--exclude "*"
)한 후, 원하는 파일만 포함(--include "pattern"
)하는 방식을 사용합니다.
예시: 확장자가 .jpg
인 파일만 업로드
aws s3 cp ./images/ s3://your-bucket-name/image_archive/ --recursive --exclude "*" --include "*.jpg"
--exclude "*"
: 일단 모든 파일을 복사 대상에서 제외합니다.--include "*.jpg"
: 그 후, 확장자가.jpg
인 파일만 다시 복사 대상에 포함시킵니다. 결과적으로.jpg
파일만 S3로 업로드됩니다.
2.3. --exclude
와 --include
조합 활용 (순서의 중요성!)
여러 개의 --exclude
와 --include
옵션을 조합하여 더 복잡한 조건을 만들 수 있습니다. 다시 한번 강조하지만, 옵션이 적용되는 순서가 결과에 결정적인 영향을 미칩니다. 필터는 왼쪽에서 오른쪽으로 순차적으로 적용됩니다.
상황 예시: 로컬 디렉토리에 다음과 같은 파일들이 있다고 가정해봅시다.
MyFile1.txt
MyFile2.log
MyConfig.json
SpecialReport.txt
TempFileA.tmp
TempFileB.tmp
예시 1: 모든 .tmp
파일은 제외하고, MyFile
로 시작하는 .txt
파일만 포함하여 업로드
aws s3 cp ./ s3://your-bucket-name/filtered_upload/ --recursive \
--exclude "*.tmp" \
--exclude "*" \
--include "MyFile*.txt"
--exclude "*.tmp"
:.tmp
파일들을 먼저 제외합니다. (TempFileA.tmp
,TempFileB.tmp
제외됨)--exclude "*"
: 나머지 모든 파일들을 제외합니다. (이 시점에서는 아무것도 선택되지 않음)--include "MyFile*.txt"
:MyFile
로 시작하는.txt
파일들을 다시 포함합니다. (MyFile1.txt
선택됨)- 결과:
MyFile1.txt
만 업로드됩니다. (SpecialReport.txt
는 두 번째 exclude에서 걸러짐)
- 결과:
예시 2: 기본적으로 모든 파일을 업로드하되, .log
파일은 제외하고, MyConfig.json
은 반드시 포함
이런 경우는 --include
를 먼저 쓰는 것이 직관적이지 않을 수 있습니다. 필터는 순서대로 적용되므로, 일반적인 규칙을 먼저 적용하고 예외를 두는 방식이 효과적입니다.
aws s3 cp ./ s3://your-bucket-name/smart_upload/ --recursive \
--exclude "*.log" \
--include "MyConfig.json"
--exclude "*.log"
:.log
파일을 제외합니다. (MyFile2.log
제외됨)--include "MyConfig.json"
:MyConfig.json
파일을 포함시킵니다. (이미 이전 단계에서 제외되지 않았으므로 계속 포함 상태)- 결과:
MyFile1.txt
,MyConfig.json
,SpecialReport.txt
,TempFileA.tmp
,TempFileB.tmp
가 업로드됩니다.MyFile2.log
는 제외됩니다. - 만약 순서가 바뀌어
--include "MyConfig.json"
다음에--exclude "*.log"
가 온다면MyConfig.json
은.log
가 아니므로 여전히 포함됩니다. 이 예제에서는 순서가 결과에 큰 영향을 미치진 않지만, 복잡한 경우 중요합니다.
- 결과:
예시 3 (원문 예시 각색): .txt
파일은 제외하지만, MyFile
로 시작하는 .txt
는 포함하고, 그 중 MyFile?.txt
(한 글자 와일드카드) 형식은 다시 제외
(로컬 파일: MyFile1.txt
, MyFile2.rtf
, MyFile88.txt
)
aws s3 cp . s3://my-bucket/path --recursive \
--exclude "*.txt" \
--include "MyFile*.txt" \
--exclude "MyFile?.txt"
--exclude "*.txt"
: 모든.txt
파일을 제외합니다. (MyFile1.txt
,MyFile88.txt
제외됨.MyFile2.rtf
는 살아남음)--include "MyFile*.txt"
:MyFile
로 시작하는.txt
파일을 다시 포함시킵니다. (MyFile1.txt
,MyFile88.txt
다시 포함됨. 현재 대상:MyFile1.txt
,MyFile2.rtf
,MyFile88.txt
)--exclude "MyFile?.txt"
:MyFile
다음에 한 글자만 오는.txt
파일을 제외합니다. (MyFile1.txt
제외됨)- 결과:
MyFile2.rtf
,MyFile88.txt
가 복사됩니다.
- 결과:
이처럼 필터의 순서를 잘 이해하고 조합하면 매우 정교한 파일 선택이 가능합니다.
3. 업로드/다운로드 결과 확인 팁
많은 파일을 옮긴 후에는 제대로 전송되었는지 확인하는 것이 중요합니다. S3 콘솔에서는 객체 수가 많을 경우 '999+' 등으로 표시되어 정확한 개수 파악이 어려울 수 있습니다. 이때 CLI를 사용하면 편리합니다.
aws s3 ls s3://your-bucket-name/your-prefix/ --recursive --human-readable --summarize
ls
: S3 객체 목록을 보여줍니다.--recursive
: 지정된 prefix 하위의 모든 객체를 보여줍니다.--human-readable
: 파일 크기를 KB, MB, GB 등 사람이 읽기 쉬운 형태로 보여줍니다.--summarize
: 총 객체 수와 총 크기를 요약해서 보여줍니다.
마무리
AWS S3 CLI의 --recursive
, --exclude
, --include
옵션은 대량의 파일을 S3와 주고받을 때 매우 유용합니다. 처음에는 필터 순서가 헷갈릴 수 있지만, 몇 번 사용해보면서 익숙해지면 복잡한 요구사항도 손쉽게 처리할 수 있습니다. 특히 자동화 스크립트나 대용량 데이터 마이그레이션 작업 시 이 옵션들의 진가를 발휘하게 될 것입니다.
더 자세한 내용은 AWS CLI 공식 문서를 참고하시는 것이 좋습니다.