Mengunggah file ke akun S3 dari baris perintah Linux

75

Saya punya beberapa file besar yang tersimpan di akun yang di-host di Linux yang perlu saya unggah ke akun S3 saya. Saya tidak ingin mengunduhnya terlebih dahulu dan kemudian mengunggahnya ke S3.

Apakah ada cara saya bisa "mengunggah" melalui baris perintah Linux? Atau dapatkah saya mengaksesnya melalui situs web yang bekerja dengan Lynx?

silikonpi
sumber

Jawaban:

30

S3cmd melakukan apa yang Anda inginkan. Mengunggah dan mengunduh file, menyinkronkan direktori dan membuat ember.

S3cmd adalah alat baris perintah dan klien gratis untuk mengunggah, mengambil dan mengelola data di Amazon S3 dan penyedia layanan penyimpanan cloud lainnya yang menggunakan protokol S3, seperti Google Cloud Storage atau DreamHost DreamObjects. Ini sangat cocok untuk pengguna listrik yang terbiasa dengan program-program baris perintah. Ini juga ideal untuk skrip batch dan cadangan otomatis ke S3, dipicu dari cron, dll.

Alister Bulman
sumber
bekerja seperti pesona!
siliconpi
98

Amazon juga menyediakan alat CLI mereka sendiri sekarang.

Dari http://aws.amazon.com/cli/

Dengan menggunakan sintaks yang sudah dikenal, Anda dapat melihat konten bucket S3 Anda dalam daftar berbasis direktori.

$ aws s3 ls s3://mybucket
      LastWriteTime     Length Name
      -------------     ------ ----
                           PRE myfolder/
2013-09-03 10:00:00       1234 myfile.txt
...

Anda dapat melakukan unggahan berulang dan unduhan banyak file dalam satu perintah tingkat folder. AWS CLI akan menjalankan transfer ini secara paralel untuk meningkatkan kinerja.

$ aws s3 cp myfolder s3://mybucket/myfolder --recursive
upload: myfolder/file1.txt to s3://mybucket/myfolder/file1.txt
upload: myfolder/subfolder/file1.txt to s3://mybucket/myfolder/subfolder/file1.txt
...

Perintah sinkronisasi memudahkan untuk menyinkronkan konten folder lokal dengan salinan di ember S3.

$ aws s3 sync myfolder s3://mybucket/myfolder --exclude *.tmp
upload: myfolder/newfile.txt to s3://mybucket/myfolder/newfile.txt
...

Dokumentasi untuk perintah terkait file ada di sini .

Drew Noakes
sumber
5
jawaban paling lengkap! :)
SergioFilhow
26

Jika Anda tidak dapat (mungkin Anda menggunakan host bersama) atau tidak ingin menginstal alat tambahan, Anda dapat menggunakan bash, curl, dan openssl.

http://tmont.com/blargh/2014/1/uploading-to-s3-in-bash

file=/path/to/file/to/upload.tar.gz
bucket=your-bucket
resource="/${bucket}/${file}"
contentType="application/x-compressed-tar"
dateValue=`date -R`
stringToSign="PUT\n\n${contentType}\n${dateValue}\n${resource}"
s3Key=xxxxxxxxxxxxxxxxxxxx
s3Secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
signature=`echo -en ${stringToSign} | openssl sha1 -hmac ${s3Secret} -binary | base64`
curl -L -X PUT -T "${file}" \
  -H "Host: ${bucket}.s3.amazonaws.com" \
  -H "Date: ${dateValue}" \
  -H "Content-Type: ${contentType}" \
  -H "Authorization: AWS ${s3Key}:${signature}" \
  https://${bucket}.s3.amazonaws.com/${file}

Perhatikan bahwa saya memodifikasi skrip ini dari yang ada di tautan di atas. Saya menambahkan -Lopsi karena AWS dapat memasukkan redirect di sana. The -Lpilihan akan mengikuti redirect untuk Anda.

Satu peringatan lainnya. Ini tidak akan berfungsi untuk file yang lebih besar dari 5GB. Itu memerlukan unggahan multi-bagian yang membutuhkan skrip yang lebih rumit.

filum
sumber
12

Skrip shell yang sesuai dengan POSIX yang hanya membutuhkan openssl, curl, dan sed; mendukung AWS Signature Version 4, yang diperlukan untuk wilayah eu-central-1(Frankfurt) dan direkomendasikan untuk yang lain:

https://gist.github.com/vszakats/2917d28a951844ab80b1

#!/bin/sh -u

# To the extent possible under law, Viktor Szakats (vszakats.net)
# has waived all copyright and related or neighboring rights to this
# script.
# CC0 - https://creativecommons.org/publicdomain/zero/1.0/

# Upload a file to Amazon AWS S3 using Signature Version 4
#
# docs:
#    https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
#
# requires:
#    curl, openssl 1.x, GNU sed, LF EOLs in this file

fileLocal="${1:-example-local-file.ext}"
bucket="${2:-example-bucket}"
region="${3:-}"
storageClass="${4:-STANDARD}"  # or 'REDUCED_REDUNDANCY'

m_openssl() {
  if [ -f /usr/local/opt/[email protected]/bin/openssl ]; then
    /usr/local/opt/[email protected]/bin/openssl "$@"
  elif [ -f /usr/local/opt/openssl/bin/openssl ]; then
    /usr/local/opt/openssl/bin/openssl "$@"
  else
    openssl "$@"
  fi
}

m_sed() {
  if which gsed > /dev/null 2>&1; then
    gsed "$@"
  else
    sed "$@"
  fi
}

awsStringSign4() {
  kSecret="AWS4$1"
  kDate=$(printf         '%s' "$2" | m_openssl dgst -sha256 -hex -mac HMAC -macopt "key:${kSecret}"     2>/dev/null | m_sed 's/^.* //')
  kRegion=$(printf       '%s' "$3" | m_openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${kDate}"    2>/dev/null | m_sed 's/^.* //')
  kService=$(printf      '%s' "$4" | m_openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${kRegion}"  2>/dev/null | m_sed 's/^.* //')
  kSigning=$(printf 'aws4_request' | m_openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${kService}" 2>/dev/null | m_sed 's/^.* //')
  signedString=$(printf  '%s' "$5" | m_openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${kSigning}" 2>/dev/null | m_sed 's/^.* //')
  printf '%s' "${signedString}"
}

iniGet() {
  # based on: https://stackoverflow.com/questions/22550265/read-certain-key-from-certain-section-of-ini-file-sed-awk#comment34321563_22550640
  printf '%s' "$(m_sed -n -E "/\[$2\]/,/\[.*\]/{/$3/s/(.*)=[ \\t]*(.*)/\2/p}" "$1")"
}

# Initialize access keys

if [ -z "${AWS_CONFIG_FILE:-}" ]; then
  if [ -z "${AWS_ACCESS_KEY:-}" ]; then
    echo 'AWS_CONFIG_FILE or AWS_ACCESS_KEY/AWS_SECRET_KEY envvars not set.'
    exit 1
  else
    awsAccess="${AWS_ACCESS_KEY}"
    awsSecret="${AWS_SECRET_KEY}"
    awsRegion='us-east-1'
  fi
else
  awsProfile='default'

  # Read standard aws-cli configuration file
  # pointed to by the envvar AWS_CONFIG_FILE
  awsAccess="$(iniGet "${AWS_CONFIG_FILE}" "${awsProfile}" 'aws_access_key_id')"
  awsSecret="$(iniGet "${AWS_CONFIG_FILE}" "${awsProfile}" 'aws_secret_access_key')"
  awsRegion="$(iniGet "${AWS_CONFIG_FILE}" "${awsProfile}" 'region')"
fi

# Initialize defaults

fileRemote="${fileLocal}"

if [ -z "${region}" ]; then
  region="${awsRegion}"
fi

echo "Uploading" "${fileLocal}" "->" "${bucket}" "${region}" "${storageClass}"
echo "| $(uname) | $(m_openssl version) | $(m_sed --version | head -1) |"

# Initialize helper variables

httpReq='PUT'
authType='AWS4-HMAC-SHA256'
service='s3'
baseUrl=".${service}.amazonaws.com"
dateValueS=$(date -u +'%Y%m%d')
dateValueL=$(date -u +'%Y%m%dT%H%M%SZ')
if hash file 2>/dev/null; then
  contentType="$(file -b --mime-type "${fileLocal}")"
else
  contentType='application/octet-stream'
fi

# 0. Hash the file to be uploaded

if [ -f "${fileLocal}" ]; then
  payloadHash=$(m_openssl dgst -sha256 -hex < "${fileLocal}" 2>/dev/null | m_sed 's/^.* //')
else
  echo "File not found: '${fileLocal}'"
  exit 1
fi

# 1. Create canonical request

# NOTE: order significant in ${headerList} and ${canonicalRequest}

headerList='content-type;host;x-amz-content-sha256;x-amz-date;x-amz-server-side-encryption;x-amz-storage-class'

canonicalRequest="\
${httpReq}
/${fileRemote}

content-type:${contentType}
host:${bucket}${baseUrl}
x-amz-content-sha256:${payloadHash}
x-amz-date:${dateValueL}
x-amz-server-side-encryption:AES256
x-amz-storage-class:${storageClass}

${headerList}
${payloadHash}"

# Hash it

canonicalRequestHash=$(printf '%s' "${canonicalRequest}" | m_openssl dgst -sha256 -hex 2>/dev/null | m_sed 's/^.* //')

# 2. Create string to sign

stringToSign="\
${authType}
${dateValueL}
${dateValueS}/${region}/${service}/aws4_request
${canonicalRequestHash}"

# 3. Sign the string

signature=$(awsStringSign4 "${awsSecret}" "${dateValueS}" "${region}" "${service}" "${stringToSign}")

# Upload

curl -s -L --proto-redir =https -X "${httpReq}" -T "${fileLocal}" \
  -H "Content-Type: ${contentType}" \
  -H "Host: ${bucket}${baseUrl}" \
  -H "X-Amz-Content-SHA256: ${payloadHash}" \
  -H "X-Amz-Date: ${dateValueL}" \
  -H "X-Amz-Server-Side-Encryption: AES256" \
  -H "X-Amz-Storage-Class: ${storageClass}" \
  -H "Authorization: ${authType} Credential=${awsAccess}/${dateValueS}/${region}/${service}/aws4_request, SignedHeaders=${headerList}, Signature=${signature}" \
  "https://${bucket}${baseUrl}/${fileRemote}"

Perhatikan, skrip akan mengaktifkan sisi server

Enkripsi AES256 secara default.

vszakats
sumber
Untuk mesin pencari: Ini adalah solusi yang tepat untuk eu-central-1 dan secara umum jika Anda mendapatkan kesalahanThe authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256
Steen
3

Atau Anda dapat mencoba https://github.com/minio/mc

mcmenyediakan alat minimal untuk bekerja dengan penyimpanan cloud dan sistem file Amazon S3 yang kompatibel. Ini memiliki fitur seperti unggah yang dapat dilanjutkan, bilah progres, salinan paralel. mcditulis dalam Golang dan dirilis di bawah lisensi Apache v2.

Harshavardhana
sumber
Ini jawaban yang bagus. Saya tidak perlu ingin melakukannya dalam bash, seperti yang disarankan (baik) lainnya. Saya hanya tidak ingin menginstal semua dependensi yang dibutuhkan awscli.
Michael Barton
1

Saya menemukan binding AWS Python dalam botopaket ( pip install boto) sangat membantu untuk mengunggah data ke S3.

Script berikut dapat disebut seperti: di python script_name.py "sub_bucket_name" "*.zip"mana sub_bucket_namemenunjukkan nama direktori di mana file harus disimpan dalam S3, dan *.zipmerupakan lintasan glob yang menunjuk satu atau lebih file yang akan diunggah:

import sys, glob, os, boto
from boto.s3.key import Key

def percent_cb(complete, total):
    sys.stdout.write('.')
    sys.stdout.flush()

id = '< your id here >'               # AWS Access Key ID
secret = '< your secret here >'       # AWS Secret Access Key
bucket_name = '< your bucket here >'  # Bucket wherein content will be stored
conn = boto.connect_s3(id, secret)    # Establish a connection to S3
bucket = conn.get_bucket(bucket_name, validate=False)  # Connect to bucket
k  = Key(bucket)                      # Connect to the bucket's key

for i in glob.glob(sys.argv[2]):      # Read in files to push to S3

        sub_bucket = sys.argv[1]  # Directory within bucket where files will be stored
        k.key = sub_bucket + "/" + os.path.basename(i) # Path each uploaded file will have on S3

        k.set_contents_from_filename(i, cb=percent_cb, num_cb=10)  # Push data to S3

        print 'Uploading %s to Amazon S3 bucket %s' % (i, bucket_name)  # Report status
duhaime
sumber