-
-
Save jessewang-arvatosystems/a8cea0f9d165f12c96c2208dd71b3dfd to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash | |
# Copyright 2017 Jesse Wang | |
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | |
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
# This script requires: | |
# - AWS CLI to be properly configured (https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html) | |
# - Account has s3:PutObject access for the target S3 bucket | |
# Usage: | |
# bash s3-multipart-upload.sh YOUR_FILE YOUR_BUCKET (OPTIONAL: PROFILE) | |
# bash s3-multipart-upload.sh files.zip my-files | |
# bash s3-multipart-upload.sh files.zip my-files second-profile | |
fileName=$1 | |
bucket=$2 | |
profile=${3-default} | |
#Set to 90 MBs as default, 100 MBs is the limit for AWS files | |
mbSplitSize=90 | |
((partSize = $mbSplitSize * 1000000)) | |
# Get main file size | |
echo "Preparing $fileName for multipart upload" | |
fileSize=`wc -c $fileName | awk '{print $1}'` | |
((parts = ($fileSize+$partSize-1) / partSize)) | |
# Get main file hash | |
mainMd5Hash=`openssl md5 -binary $fileName | base64` | |
# Make directory to store temporary parts | |
echo "Splitting $fileName into $parts temporary parts" | |
mkdir temp-parts | |
cp $fileName temp-parts/ | |
cd temp-parts | |
split -b $partSize $fileName | |
rm $fileName | |
# Create mutlipart upload | |
echo "Initiating multipart upload for $fileName" | |
uploadId=`aws s3api create-multipart-upload --bucket $bucket --key $fileName --metadata md5=$mainMd5Hash --profile $profile | jq -r '.UploadId'` | |
# Generate fileparts.json file that will be used at the end of the multipart upload | |
jsonData="{\"Parts\":[" | |
for file in * | |
do | |
((index++)) | |
echo "Uploading part $index of $parts..." | |
hashData=`openssl md5 -binary $file | base64` | |
eTag=`aws s3api upload-part --bucket $bucket --key $fileName --part-number $index --body $file --upload-id $uploadId --profile $profile | jq -r '.ETag'` | |
jsonData+="{\"ETag\":$eTag,\"PartNumber\":$index}" | |
if (( $index == $parts )) | |
then | |
jsonData+="]}" | |
else | |
jsonData+="," | |
fi | |
done | |
jq -n $jsonData > fileparts.json | |
# Complete multipart upload, check ETag to verify success | |
mainEtag=`aws s3api complete-multipart-upload --multipart-upload file://fileparts.json --bucket $bucket --key $fileName --upload-id $uploadId --profile $profile | jq -r '.ETag'` | |
if [[ $mainEtag != "" ]]; | |
then | |
echo "Successfully uploaded: $fileName to S3 bucket: $bucket" | |
else | |
echo "Something went wrong! $fileName was not uploaded to S3 bucket: $bucket" | |
fi | |
# Clean up files | |
cd .. | |
rm -R temp-parts |
Hi there, did you try something like bash s3-multipart-upload.sh files.zip 'country/province/city'
?
super helpful! - thanks
you can achieve it in two steps
1st step to upload as usual
2nd step to move the uploaded file to the destination you specify
add the following to the script :
path to the folder and subfolder using the next format: country/province/city
path=$3
change profile to $4 just as below
profile=${4-default}
at the end of the script add the following command just before # Clean up files
aws s3 mv s3://$bucket/$fileName s3://$bucket/$path/
echo "File $fileName Successfully moved to subfolder $path successfully"
I tried it and worked on my machine
Good Luck!
Hello,
I want to upload a whole folder i.e. /test-folder/*, how can I do that?
Many Thanks for the Script
@k8simulator This can be accomplished by using a for-loop and iterate each file in the folder by calling the script.
@jessewang-arvatosystems Thanks for the quick reply.
so you mean something like this?
for file in * ; do
sleep 1
./s3-multipart-upload.sh
done
but inside the s3-multipart-upload.sh script what should I but as FileName ?
Thanks
@jessewang-arvatosystems Thanks for the quick reply. so you mean something like this? for file in * ; do sleep 1 ./s3-multipart-upload.sh done
but inside the s3-multipart-upload.sh script what should I but as FileName ?
Thanks
Something like what this stackoverflow describes: https://stackoverflow.com/questions/27881739/a-script-that-iterates-over-all-files-in-folder
ex.
find /test-folder -maxdepth 1 -type f -exec ./s3-multipart-upload.sh {} YOUR_S3_BUCKET \;
@jessewang-arvatosystems
thanks for the hint, it helped me further.
But unfortunately, it is still not clear to me, what should be given as fileName in the s3-multipart-upload.sh script?
since the env "fileName" is invoked several times in the script.
The {}
part in the sample I wrote is the filename. It is a placeholder that the find
command uses.
I think it is easier to understand if you upload one file to see how it works.
Uploads "test.png" to the S3 bucket "my-files"
./s3-multipart-upload.sh test.png my-files
Uploads "pics.zip" to the S3 bucket "my-photos"
./s3-multipart-upload.sh pics.zip my-photos
Hi, How can we upload the file into sub directories.
e.g.
bucket name is country. There is a folder inside country named province. Then inside province we have city. Now I want to upload the files in city subfolder.
I tried to tweak you code. But no luck.