Skip to content

Instantly share code, notes, and snippets.

@instantiator
Last active February 21, 2025 13:02
Show Gist options
  • Select an option

  • Save instantiator/093b1727b1cf16e77dfa3218d1957610 to your computer and use it in GitHub Desktop.

Select an option

Save instantiator/093b1727b1cf16e77dfa3218d1957610 to your computer and use it in GitHub Desktop.
A script to completely empty a versioned S3 bucket, in preparation for deletion. Run with `--help` to see the help information. Core details from this excellent StackOverflow advice: https://stackoverflow.com/a/61123579
#!/bin/bash
set -e
set -o pipefail
usage() {
cat << EOF
Dangerous script. This script will empty a specified bucket.
Options:
-b <bucket> --bucket <bucket> Sets the bucket to empty
-r <region> --region <region> Sets the region (default: eu-west-2)
-y --yes Confirm that you really wish to do this
-h --help Prints this help message and exits
EOF
}
# prevent paging
export AWS_PAGER=""
# defaults
REGION=eu-west-2
while [ -n "$1" ]; do
case $1 in
-y | --yes)
CONFIRMATION=yes
;;
-r | --region)
shift
REGION=$1
;;
-b | --bucket)
shift
BUCKET=$1
;;
-h | --help)
usage
exit 0
;;
*)
echo -e "Unknown option $1...\n" >&2
usage
exit 1
;;
esac
shift
done
if [ -z "$BUCKET" ]; then
echo "Please provide the bucket name."
echo
usage
exit 1
fi
if [ -z "$CONFIRMATION" ]; then
echo "This will delete everything in bucket: $BUCKET"
read -p "Are you sure? " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
# check if the bucket exists
S3LS=$(aws s3 ls --region $REGION | grep "$BUCKET" || true)
if [ -z "${S3LS}" ]; then
echo "Bucket $BUCKET does not exist."
exit 0
fi
# delete everything in the bucket (unversioned, optimistic)
echo "Naive deletion of all objects in bucket $BUCKET..."
aws s3 rm s3://$BUCKET --region $REGION --recursive
echo
# versioned buckets also need you to delete all object versions and deletion markers
echo "Deleting all object versions and deletion markers in bucket $BUCKET..."
echo
# delete all object versions
NB_OBJECTS=$(aws s3api list-object-versions --bucket ${BUCKET} --query='length(Versions[*] || `[]` )' | awk '{ print $1 }')
echo "Found: ${NB_OBJECTS} object Versions to remove..."
if [[ "$NB_OBJECTS" != "0" ]]; then
start=$SECONDS
while [[ $NB_OBJECTS -gt 0 ]]
do
aws s3api delete-objects --bucket ${BUCKET} --delete "$(aws s3api list-object-versions --bucket ${BUCKET} --max-items 500 --query='{Objects: Versions[0:500].{Key:Key,VersionId:VersionId}}')" --query 'length(Deleted[*] || `[]` )' > /dev/null
NB_OBJECTS=$((NB_OBJECTS > 500 ? NB_OBJECTS - 500 : 0))
echo " - Remaining: $NB_OBJECTS ($(( SECONDS - start ))s)"
done
fi
echo
# delete all deletion markers
NB_OBJECTS=$(aws s3api list-object-versions --bucket ${BUCKET} --query='length(DeleteMarkers[*] || `[]` )' | awk '{ print $1 }')
echo "Found: ${NB_OBJECTS} DeleteMarkers to remove..."
if [[ "$NB_OBJECTS" != "0" ]]; then
start=$SECONDS
while [[ $NB_OBJECTS -gt 0 ]]
do
aws s3api delete-objects --bucket ${BUCKET} --delete "$(aws s3api list-object-versions --bucket ${BUCKET} --max-items 500 --query='{Objects: DeleteMarkers[0:500].{Key:Key,VersionId:VersionId}}')" --query 'length(Deleted[*] || `[]` )' > /dev/null
NB_OBJECTS=$((NB_OBJECTS > 500 ? NB_OBJECTS - 500 : 0))
echo " - Remaining: $NB_OBJECTS ($(( SECONDS - start ))s)"
done
fi
echo
# fin
echo "Bucket $BUCKET has been emptied."
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment