当前位置: 移动技术网 > 网络运营>服务器>Linux > 编写shell脚本将VPS上的数据备份到Dropbox网盘的方法

编写shell脚本将VPS上的数据备份到Dropbox网盘的方法

2017年12月12日  | 移动技术网网络运营  | 我要评论
看到有人用dropbox备份网站数据,所以今天也试了一下,记得以前是一个python脚本,这是用的是bash 脚本,利用dropbox的api来上传下载的,很方便,脚本的地

看到有人用dropbox备份网站数据,所以今天也试了一下,记得以前是一个python脚本,这是用的是bash 脚本,利用dropbox的api来上传下载的,很方便,脚本的地址是dropbox-uploader/dropbox_uploader.sh at master · andreafabrizi/dropbox-uploader · github ,感谢作者分享这个脚本。

可以到git下载dropbox_uploader.sh,地址为:https://github.com/andreafabrizi/dropbox-uploader
或者也可以直接拷贝代码,保存为dropbox_uploader.sh,注意拷贝的时候最好是复制到文本编辑器里面,如notepad++之类的

#!/usr/bin/env bash
#
# dropbox uploader
#
# copyright (c) 2010-2014 andrea fabrizi <andrea.fabrizi@gmail.com>
#
# this program is free software; you can redistribute it and/or modify
# it under the terms of the gnu general public license as published by
# the free software foundation; either version 2 of the license, or
# (at your option) any later version.
#
# this program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose. see the
# gnu general public license for more details.
#
# you should have received a copy of the gnu general public license
# along with this program; if not, write to the free software
# foundation, inc., 59 temple place - suite 330, boston, ma 02111-1307, usa.
#

#default configuration file
config_file=~/.dropbox_uploader

#default chunk size in mb for the upload process
#it is recommended to increase this value only if you have enough free space on your /tmp partition
#lower values may increase the number of http requests
chunk_size=4

#curl location
#if not set, curl will be searched into the $path
#curl_bin="/usr/bin/curl"

#default values
tmp_dir="/tmp"
debug=0
quiet=0
show_progressbar=0
skip_existing_files=0
error_status=0

#don't edit these...
api_request_token_url="https://api.dropbox.com/1/oauth/request_token"
api_user_auth_url="https://www2.dropbox.com/1/oauth/authorize"
api_access_token_url="https://api.dropbox.com/1/oauth/access_token"
api_chunked_upload_url="https://api-content.dropbox.com/1/chunked_upload"
api_chunked_upload_commit_url="https://api-content.dropbox.com/1/commit_chunked_upload"
api_upload_url="https://api-content.dropbox.com/1/files_put"
api_download_url="https://api-content.dropbox.com/1/files"
api_delete_url="https://api.dropbox.com/1/fileops/delete"
api_move_url="https://api.dropbox.com/1/fileops/move"
api_copy_url="https://api.dropbox.com/1/fileops/copy"
api_metadata_url="https://api.dropbox.com/1/metadata"
api_info_url="https://api.dropbox.com/1/account/info"
api_mkdir_url="https://api.dropbox.com/1/fileops/create_folder"
api_shares_url="https://api.dropbox.com/1/shares"
app_create_url="https://www2.dropbox.com/developers/apps"
response_file="$tmp_dir/du_resp_$random"
chunk_file="$tmp_dir/du_chunk_$random"
temp_file="$tmp_dir/du_tmp_$random"
bin_deps="sed basename date grep stat dd mkdir"
version="0.14"

umask 077

#check the shell
if [ -z "$bash_version" ]; then
  echo -e "error: this script requires the bash shell!"
  exit 1
fi

shopt -s nullglob #bash allows filename patterns which match no files to expand to a null string, rather than themselves
shopt -s dotglob #bash includes filenames beginning with a "." in the results of filename expansion

#look for optional config file parameter
while getopts ":qpskdf:" opt; do
  case $opt in

  f)
   config_file=$optarg
  ;;

  d)
   debug=1
  ;;

  q)
   quiet=1
  ;;

  p)
   show_progressbar=1
  ;;

  k)
   curl_accept_certificates="-k"
  ;;

  s)
   skip_existing_files=1
  ;;

  \?)
   echo "invalid option: -$optarg" >&2
   exit 1
  ;;

  :)
   echo "option -$optarg requires an argument." >&2
   exit 1
  ;;

 esac
done

if [[ $debug != 0 ]]; then
  echo $version
  set -x
  response_file="$tmp_dir/du_resp_debug"
fi

if [[ $curl_bin == "" ]]; then
  bin_deps="$bin_deps curl"
  curl_bin="curl"
fi

#dependencies check
which $bin_deps > /dev/null
if [[ $? != 0 ]]; then
  for i in $bin_deps; do
    which $i > /dev/null ||
      not_found="$i $not_found"
  done
  echo -e "error: required program could not be found: $not_found"
  exit 1
fi

#check if readlink is installed and supports the -m option
#it's not necessary, so no problem if it's not installed
which readlink > /dev/null
if [[ $? == 0 && $(readlink -m "//test" 2> /dev/null) == "/test" ]]; then
  have_readlink=1
else
  have_readlink=0
fi

#forcing to use the builtin printf, if it's present, because it's better
#otherwise the external printf program will be used
#note that the external printf command can cause character encoding issues!
builtin printf "" 2> /dev/null
if [[ $? == 0 ]]; then
  printf="builtin printf"
  printf_opt="-v o"
else
  printf=$(which printf)
  if [[ $? != 0 ]]; then
    echo -e "error: required program could not be found: printf"
  fi
  printf_opt=""
fi

#print the message based on $quiet variable
function print
{
  if [[ $quiet == 0 ]]; then
	  echo -ne "$1";
  fi
}

#returns unix timestamp
function utime
{
  echo $(date +%s)
}

#remove temporary files
function remove_temp_files
{
  if [[ $debug == 0 ]]; then
    rm -fr "$response_file"
    rm -fr "$chunk_file"
    rm -fr "$temp_file"
  fi
}

#returns the file size in bytes
# generic gnu linux: linux-gnu
# windows cygwin:  cygwin
# raspberry pi:   linux-gnueabihf
# macosx:      darwin10.0
# freebsd:      freebsd
# qnap:       linux-gnueabi
# ios:        darwin9
function file_size
{
  #some embedded linux devices
  if [[ $ostype == "linux-gnueabi" || $ostype == "linux-gnu" ]]; then
    stat -c "%s" "$1"
    return

  #generic unix
  elif [[ ${ostype:0:5} == "linux" || $ostype == "cygwin" || ${ostype:0:7} == "solaris" ]]; then
    stat --format="%s" "$1"
    return

  #bsd, osx and other oss
  else
    stat -f "%z" "$1"
    return
  fi
}

#usage
function usage
{
  echo -e "dropbox uploader v$version"
  echo -e "andrea fabrizi - andrea.fabrizi@gmail.com\n"
  echo -e "usage: $0 command [parameters]..."
  echo -e "\ncommands:"

  echo -e "\t upload  <local_file/dir ...> <remote_file/dir>"
  echo -e "\t download <remote_file/dir> [local_file/dir]"
  echo -e "\t delete  <remote_file/dir>"
  echo -e "\t move   <remote_file/dir> <remote_file/dir>"
  echo -e "\t copy   <remote_file/dir> <remote_file/dir>"
  echo -e "\t mkdir  <remote_dir>"
  echo -e "\t list   [remote_dir]"
  echo -e "\t share  <remote_file>"
  echo -e "\t info"
  echo -e "\t unlink"

  echo -e "\noptional parameters:"
  echo -e "\t-f <filename> load the configuration file from a specific file"
  echo -e "\t-s      skip already existing files when download/upload. default: overwrite"
  echo -e "\t-d      enable debug mode"
  echo -e "\t-q      quiet mode. don't show messages"
  echo -e "\t-p      show curl progress meter"
  echo -e "\t-k      doesn't check for ssl certificates (insecure)"

  echo -en "\nfor more info and examples, please see the readme file.\n\n"
  remove_temp_files
  exit 1
}

#check the curl exit code
function check_http_response
{
  code=$?

  #checking curl exit code
  case $code in

    #ok
    0)

    ;;

    #proxy error
    5)
      print "\nerror: couldn't resolve proxy. the given proxy host could not be resolved.\n"

      remove_temp_files
      exit 1
    ;;

    #missing ca certificates
    60|58)
      print "\nerror: curl is not able to performs peer ssl certificate verification.\n"
      print "please, install the default ca-certificates bundle.\n"
      print "to do this in a debian/ubuntu based system, try:\n"
      print " sudo apt-get install ca-certificates\n\n"
      print "if the problem persists, try to use the -k option (insecure).\n"

      remove_temp_files
      exit 1
    ;;

    6)
      print "\nerror: couldn't resolve host.\n"

      remove_temp_files
      exit 1
    ;;

    7)
      print "\nerror: couldn't connect to host.\n"

      remove_temp_files
      exit 1
    ;;

  esac

  #checking response file for generic errors
  if grep -q "http/1.1 400" "$response_file"; then
    error_msg=$(sed -n -e 's/{"error": "\([^"]*\)"}/\1/p' "$response_file")

    case $error_msg in
       *access?attempt?failed?because?this?app?is?not?configured?to?have*)
        echo -e "\nerror: the permission type/access level configured doesn't match the dropbox app settings!\nplease run \"$0 unlink\" and try again."
        exit 1
      ;;
    esac

  fi

}

#urlencode
function urlencode
{
  local string="${1}"
  local strlen=${#string}
  local encoded=""

  for (( pos=0 ; pos<strlen ; pos++ )); do
    c=${string:$pos:1}
    case "$c" in
      [-_.~a-za-z0-9] ) o="${c}" ;;
      * ) $printf $printf_opt '%%%02x' "'$c"
    esac
    encoded+="${o}"
  done

  echo "$encoded"
}

function normalize_path
{
  path=$(echo -e "$1")
  if [[ $have_readlink == 1 ]]; then
    readlink -m "$path"
  else
    echo "$path"
  fi
}

#check if it's a file or directory
#returns file/dir/err
function db_stat
{
  local file=$(normalize_path "$1")

  #checking if it's a file or a directory
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" "$api_metadata_url/$access_level/$(urlencode "$file")?oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random" 2> /dev/null
  check_http_response

  #even if the file/dir has been deleted from dropbox we receive a 200 ok response
  #so we must check if the file exists or if it has been deleted
  if grep -q "\"is_deleted\":" "$response_file"; then
    local is_deleted=$(sed -n 's/.*"is_deleted":.\([^,]*\).*/\1/p' "$response_file")
  else
    local is_deleted="false"
  fi

  #exits...
  grep -q "^http/1.1 200 ok" "$response_file"
  if [[ $? == 0 && $is_deleted != "true" ]]; then

    local is_dir=$(sed -n 's/^\(.*\)\"contents":.\[.*/\1/p' "$response_file")

    #it's a directory
    if [[ $is_dir != "" ]]; then
      echo "dir"
    #it's a file
    else
      echo "file"
    fi

  #doesn't exists
  else
    echo "err"
  fi
}

#generic upload wrapper around db_upload_file and db_upload_dir functions
#$1 = local source file/dir
#$2 = remote destination file/dir
function db_upload
{
  local src=$(normalize_path "$1")
  local dst=$(normalize_path "$2")

  #checking if the file/dir exists
  if [[ ! -e $src && ! -d $src ]]; then
    print " > no such file or directory: $src\n"
    error_status=1
    return
  fi

  #checking if the file/dir has read permissions
  if [[ ! -r $src ]]; then
    print " > error reading file $src: permission denied\n"
    error_status=1
    return
  fi

  #checking if dst it's a folder or if it doesn' exists (in this case will be the destination name)
  type=$(db_stat "$dst")
  if [[ $type == "dir" ]]; then
    local filename=$(basename "$src")
    dst="$dst/$filename"
  fi

  #it's a directory
  if [[ -d $src ]]; then
    db_upload_dir "$src" "$dst"

  #it's a file
  elif [[ -e $src ]]; then
    db_upload_file "$src" "$dst"

  #unsupported object...
  else
    print " > skipping not regular file \"$src\"\n"
  fi
}

#generic upload wrapper around db_chunked_upload_file and db_simple_upload_file
#the final upload function will be choosen based on the file size
#$1 = local source file
#$2 = remote destination file
function db_upload_file
{
  local file_src=$(normalize_path "$1")
  local file_dst=$(normalize_path "$2")

  shopt -s nocasematch

  #checking not allowed file names
  basefile_dst=$(basename "$file_dst")
  if [[ $basefile_dst == "thumbs.db" || \
     $basefile_dst == "desktop.ini" || \
     $basefile_dst == ".ds_store" || \
     $basefile_dst == "icon\r" || \
     $basefile_dst == ".dropbox" || \
     $basefile_dst == ".dropbox.attr" \
    ]]; then
    print " > skipping not allowed file name \"$file_dst\"\n"
    return
  fi

  shopt -u nocasematch

  #checking file size
  file_size=$(file_size "$file_src")

  #checking if the file already exists
  type=$(db_stat "$file_dst")
  if [[ $type != "err" && $skip_existing_files == 1 ]]; then
    print " > skipping already existing file \"$file_dst\"\n"
    return
  fi

  if [[ $file_size -gt 157286000 ]]; then
    #if the file is greater than 150mb, the chunked_upload api will be used
    db_chunked_upload_file "$file_src" "$file_dst"
  else
    db_simple_upload_file "$file_src" "$file_dst"
  fi

}

#simple file upload
#$1 = local source file
#$2 = remote destination file
function db_simple_upload_file
{
  local file_src=$(normalize_path "$1")
  local file_dst=$(normalize_path "$2")

  if [[ $show_progressbar == 1 && $quiet == 0 ]]; then
    curl_parameters="--progress-bar"
    line_cr="\n"
  else
    curl_parameters="-s"
    line_cr=""
  fi

  print " > uploading \"$file_src\" to \"$file_dst\"... $line_cr"
  $curl_bin $curl_accept_certificates $curl_parameters -i --globoff -o "$response_file" --upload-file "$file_src" "$api_upload_url/$access_level/$(urlencode "$file_dst")?oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random"
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then
    print "done\n"
  else
    print "failed\n"
    print "an error occurred requesting /upload\n"
    error_status=1
  fi
}

#chunked file upload
#$1 = local source file
#$2 = remote destination file
function db_chunked_upload_file
{
  local file_src=$(normalize_path "$1")
  local file_dst=$(normalize_path "$2")

  print " > uploading \"$file_src\" to \"$file_dst\""

  local file_size=$(file_size "$file_src")
  local offset=0
  local upload_id=""
  local upload_error=0
  local chunk_params=""

  #uploading chunks...
  while ([[ $offset != $file_size ]]); do

    let offset_mb=$offset/1024/1024

    #create the chunk
    dd if="$file_src" of="$chunk_file" bs=1048576 skip=$offset_mb count=$chunk_size 2> /dev/null

    #only for the first request these parameters are not included
    if [[ $offset != 0 ]]; then
      chunk_params="upload_id=$upload_id&offset=$offset"
    fi

    #uploading the chunk...
    $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --upload-file "$chunk_file" "$api_chunked_upload_url?$chunk_params&oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random" 2> /dev/null
    check_http_response

    #check
    if grep -q "^http/1.1 200 ok" "$response_file"; then
      print "."
      upload_error=0
      upload_id=$(sed -n 's/.*"upload_id": *"*\([^"]*\)"*.*/\1/p' "$response_file")
      offset=$(sed -n 's/.*"offset": *\([^}]*\).*/\1/p' "$response_file")
    else
      print "*"
      let upload_error=$upload_error+1

      #on error, the upload is retried for max 3 times
      if [[ $upload_error -gt 2 ]]; then
        print " failed\n"
        print "an error occurred requesting /chunked_upload\n"
        error_status=1
        return
      fi
    fi

  done

  upload_error=0

  #commit the upload
  while (true); do

    $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "upload_id=$upload_id&oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random" "$api_chunked_upload_commit_url/$access_level/$(urlencode "$file_dst")" 2> /dev/null
    check_http_response

    #check
    if grep -q "^http/1.1 200 ok" "$response_file"; then
      print "."
      upload_error=0
      break
    else
      print "*"
      let upload_error=$upload_error+1

      #on error, the commit is retried for max 3 times
      if [[ $upload_error -gt 2 ]]; then
        print " failed\n"
        print "an error occurred requesting /commit_chunked_upload\n"
        error_status=1
        return
      fi
    fi

  done

  print " done\n"
}

#directory upload
#$1 = local source dir
#$2 = remote destination dir
function db_upload_dir
{
  local dir_src=$(normalize_path "$1")
  local dir_dst=$(normalize_path "$2")

  #creatig remote directory
  db_mkdir "$dir_dst"

  for file in "$dir_src/"*; do
    db_upload "$file" "$dir_dst"
  done
}

#returns the free space on dropbox in bytes
function db_free_quota
{
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random" "$api_info_url" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then

    quota=$(sed -n 's/.*"quota": \([0-9]*\).*/\1/p' "$response_file")
    used=$(sed -n 's/.*"normal": \([0-9]*\).*/\1/p' "$response_file")
    let free_quota=$quota-$used
    echo $free_quota

  else
    echo 0
  fi
}

#generic download wrapper
#$1 = remote source file/dir
#$2 = local destination file/dir
function db_download
{
  local src=$(normalize_path "$1")
  local dst=$(normalize_path "$2")

  type=$(db_stat "$src")

  #it's a directory
  if [[ $type == "dir" ]]; then

    #if the dst folder is not specified, i assume that is the current directory
    if [[ $dst == "" ]]; then
      dst="."
    fi

    #checking if the destination directory exists
    if [[ ! -d $dst ]]; then
      local basedir=""
    else
      local basedir=$(basename "$src")
    fi

    local dest_dir=$(normalize_path "$dst/$basedir")
    print " > downloading \"$src\" to \"$dest_dir\"... \n"
    print " > creating local directory \"$dest_dir\"... "
    mkdir -p "$dest_dir"

    #check
    if [[ $? == 0 ]]; then
      print "done\n"
    else
      print "failed\n"
      error_status=1
      return
    fi

    #extracting directory content [...]
    #and replacing "}, {" with "}\n{"
    #i don't like this piece of code... but seems to be the only way to do this with sed, writing a portable code...
    local dir_content=$(sed -n 's/.*: \[{\(.*\)/\1/p' "$response_file" | sed 's/}, *{/}\
{/g')

    #extracting files and subfolders
    tmp_dir_content_file="${response_file}_$random"
    echo "$dir_content" | sed -n 's/.*"path": *"\([^"]*\)",.*"is_dir": *\([^"]*\),.*/\1:\2/p' > $tmp_dir_content_file

    #for each entry...
    while read -r line; do

      local file=${line%:*}
      local type=${line#*:}

      #removing unneeded /
      file=${file##*/}

      if [[ $type == "false" ]]; then
        db_download_file "$src/$file" "$dest_dir/$file"
      else
        db_download "$src/$file" "$dest_dir"
      fi

    done < $tmp_dir_content_file

    rm -fr $tmp_dir_content_file

  #it's a file
  elif [[ $type == "file" ]]; then

    #checking dst
    if [[ $dst == "" ]]; then
      dst=$(basename "$src")
    fi

    #if the destination is a directory, the file will be download into
    if [[ -d $dst ]]; then
      dst="$dst/$src"
    fi

    db_download_file "$src" "$dst"

  #doesn't exists
  else
    print " > no such file or directory: $src\n"
    error_status=1
    return
  fi
}

#simple file download
#$1 = remote source file
#$2 = local destination file
function db_download_file
{
  local file_src=$(normalize_path "$1")
  local file_dst=$(normalize_path "$2")

  if [[ $show_progressbar == 1 && $quiet == 0 ]]; then
    curl_parameters="--progress-bar"
    line_cr="\n"
  else
    curl_parameters="-s"
    line_cr=""
  fi

  #checking if the file already exists
  if [[ -e $file_dst && $skip_existing_files == 1 ]]; then
    print " > skipping already existing file \"$file_dst\"\n"
    return
  fi

  #creating the empty file, that for two reasons:
  #1) in this way i can check if the destination file is writable or not
  #2) curl doesn't automatically creates files with 0 bytes size
  dd if=/dev/zero of="$file_dst" count=0 2> /dev/null
  if [[ $? != 0 ]]; then
    print " > error writing file $file_dst: permission denied\n"
    error_status=1
    return
  fi

  print " > downloading \"$file_src\" to \"$file_dst\"... $line_cr"
  $curl_bin $curl_accept_certificates $curl_parameters --globoff -d "$response_file" -o "$file_dst" "$api_download_url/$access_level/$(urlencode "$file_src")?oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random"
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then
    print "done\n"
  else
    print "failed\n"
    rm -fr "$file_dst"
    error_status=1
    return
  fi
}

#prints account info
function db_account_info
{
  print "dropbox uploader v$version\n\n"
  print " > getting info... "
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random" "$api_info_url" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then

    name=$(sed -n 's/.*"display_name": "\([^"]*\).*/\1/p' "$response_file")
    echo -e "\n\nname:\t$name"

    uid=$(sed -n 's/.*"uid": \([0-9]*\).*/\1/p' "$response_file")
    echo -e "uid:\t$uid"

    email=$(sed -n 's/.*"email": "\([^"]*\).*/\1/p' "$response_file")
    echo -e "email:\t$email"

    quota=$(sed -n 's/.*"quota": \([0-9]*\).*/\1/p' "$response_file")
    let quota_mb=$quota/1024/1024
    echo -e "quota:\t$quota_mb mb"

    used=$(sed -n 's/.*"normal": \([0-9]*\).*/\1/p' "$response_file")
    let used_mb=$used/1024/1024
    echo -e "used:\t$used_mb mb"

    let free_mb=($quota-$used)/1024/1024
    echo -e "free:\t$free_mb mb"

    echo ""

  else
    print "failed\n"
    error_status=1
  fi
}

#account unlink
function db_unlink
{
  echo -ne "are you sure you want unlink this script from your dropbox account? [y/n]"
  read answer
  if [[ $answer == "y" ]]; then
    rm -fr "$config_file"
    echo -ne "done\n"
  fi
}

#delete a remote file
#$1 = remote file to delete
function db_delete
{
  local file_dst=$(normalize_path "$1")

  print " > deleting \"$file_dst\"... "
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random&root=$access_level&path=$(urlencode "$file_dst")" "$api_delete_url" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then
    print "done\n"
  else
    print "failed\n"
    error_status=1
  fi
}

#move/rename a remote file
#$1 = remote file to rename or move
#$2 = new file name or location
function db_move
{
  local file_src=$(normalize_path "$1")
  local file_dst=$(normalize_path "$2")

  type=$(db_stat "$file_dst")

  #if the destination it's a directory, the source will be moved into it
  if [[ $type == "dir" ]]; then
    local filename=$(basename "$file_src")
    file_dst=$(normalize_path "$file_dst/$filename")
  fi

  print " > moving \"$file_src\" to \"$file_dst\" ... "
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random&root=$access_level&from_path=$(urlencode "$file_src")&to_path=$(urlencode "$file_dst")" "$api_move_url" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then
    print "done\n"
  else
    print "failed\n"
    error_status=1
  fi
}

#copy a remote file to a remote location
#$1 = remote file to rename or move
#$2 = new file name or location
function db_copy
{
  local file_src=$(normalize_path "$1")
  local file_dst=$(normalize_path "$2")

  type=$(db_stat "$file_dst")

  #if the destination it's a directory, the source will be copied into it
  if [[ $type == "dir" ]]; then
    local filename=$(basename "$file_src")
    file_dst=$(normalize_path "$file_dst/$filename")
  fi

  print " > copying \"$file_src\" to \"$file_dst\" ... "
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random&root=$access_level&from_path=$(urlencode "$file_src")&to_path=$(urlencode "$file_dst")" "$api_copy_url" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then
    print "done\n"
  else
    print "failed\n"
    error_status=1
  fi
}

#create a new directory
#$1 = remote directory to create
function db_mkdir
{
  local dir_dst=$(normalize_path "$1")

  print " > creating directory \"$dir_dst\"... "
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random&root=$access_level&path=$(urlencode "$dir_dst")" "$api_mkdir_url" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then
    print "done\n"
  elif grep -q "^http/1.1 403 forbidden" "$response_file"; then
    print "already exists\n"
  else
    print "failed\n"
    error_status=1
  fi
}

#list remote directory
#$1 = remote directory
function db_list
{
  local dir_dst=$(normalize_path "$1")

  print " > listing \"$dir_dst\"... "
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" "$api_metadata_url/$access_level/$(urlencode "$dir_dst")?oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then

    local is_dir=$(sed -n 's/^\(.*\)\"contents":.\[.*/\1/p' "$response_file")

    #it's a directory
    if [[ $is_dir != "" ]]; then

      print "done\n"

      #extracting directory content [...]
      #and replacing "}, {" with "}\n{"
      #i don't like this piece of code... but seems to be the only way to do this with sed, writing a portable code...
      local dir_content=$(sed -n 's/.*: \[{\(.*\)/\1/p' "$response_file" | sed 's/}, *{/}\
{/g')

      #converting escaped quotes to unicode format
      echo "$dir_content" | sed 's/\\"/\\u0022/' > "$temp_file"

      #extracting files and subfolders
      rm -fr "$response_file"
      while read -r line; do

        local file=$(echo "$line" | sed -n 's/.*"path": *"\([^"]*\)".*/\1/p')
        local is_dir=$(echo "$line" | sed -n 's/.*"is_dir": *\([^,]*\).*/\1/p')
        local size=$(echo "$line" | sed -n 's/.*"bytes": *\([0-9]*\).*/\1/p')

        echo -e "$file:$is_dir;$size" >> "$response_file"

      done < "$temp_file"

      #looking for the biggest file size
      #to calculate the padding to use
      local padding=0
      while read -r line; do
        local file=${line%:*}
        local meta=${line##*:}
        local size=${meta#*;}

        if [[ ${#size} -gt $padding ]]; then
          padding=${#size}
        fi
      done < "$response_file"

      #for each entry, printing directories...
      while read -r line; do

        local file=${line%:*}
        local meta=${line##*:}
        local type=${meta%;*}
        local size=${meta#*;}

        #removing unneeded /
        file=${file##*/}

        if [[ $type != "false" ]]; then
          file=$(echo -e "$file")
          $printf " [d] %-${padding}s %s\n" "$size" "$file"
        fi

      done < "$response_file"

      #for each entry, printing files...
      while read -r line; do

        local file=${line%:*}
        local meta=${line##*:}
        local type=${meta%;*}
        local size=${meta#*;}

        #removing unneeded /
        file=${file##*/}

        if [[ $type == "false" ]]; then
          file=$(echo -e "$file")
          $printf " [f] %-${padding}s %s\n" "$size" "$file"
        fi

      done < "$response_file"

    #it's a file
    else
      print "failed: $dir_dst is not a directory!\n"
      error_status=1
    fi

  else
    print "failed\n"
    error_status=1
  fi
}

#share remote file
#$1 = remote file
function db_share
{
  local file_dst=$(normalize_path "$1")

  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" "$api_shares_url/$access_level/$(urlencode "$file_dst")?oauth_consumer_key=$appkey&oauth_token=$oauth_access_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_access_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random&short_url=false" 2> /dev/null
  check_http_response

  #check
  if grep -q "^http/1.1 200 ok" "$response_file"; then
    print " > share link: "
    echo $(sed -n 's/.*"url": "\([^"]*\).*/\1/p' "$response_file")
  else
    print "failed\n"
    error_status=1
  fi
}

################
#### setup ####
################

#checking for auth file
if [[ -e $config_file ]]; then

  #loading data... and change old format config if necesary.
  source "$config_file" 2>/dev/null || {
    sed -i'' 's/:/=/' "$config_file" && source "$config_file" 2>/dev/null
  }

  #checking the loaded data
  if [[ $appkey == "" || $appsecret == "" || $oauth_access_token_secret == "" || $oauth_access_token == "" ]]; then
    echo -ne "error loading data from $config_file...\n"
    echo -ne "it is recommended to run $0 unlink\n"
    remove_temp_files
    exit 1
  fi

  #back compatibility with previous dropbox uploader versions
  if [[ $access_level == "" ]]; then
    access_level="dropbox"
  fi

#new setup...
else

  echo -ne "\n this is the first time you run this script.\n\n"
  echo -ne " 1) open the following url in your browser, and log in using your account: $app_create_url\n"
  echo -ne " 2) click on \"create app\", then select \"dropbox api app\"\n"
  echo -ne " 3) select \"files and datastores\"\n"
  echo -ne " 4) now go on with the configuration, choosing the app permissions and access restrictions to your dropbox folder\n"
  echo -ne " 5) enter the \"app name\" that you prefer (e.g. myuploader$random$random$random)\n\n"

  echo -ne " now, click on the \"create app\" button.\n\n"

  echo -ne " when your new app is successfully created, please type the\n"
  echo -ne " app key, app secret and the permission type shown in the confirmation page:\n\n"

  #getting the app key and secret from the user
  while (true); do

    echo -n " # app key: "
    read appkey

    echo -n " # app secret: "
    read appsecret

    echo -n " # permission type, app folder or full dropbox [a/f]: "
    read access_level

    if [[ $access_level == "a" ]]; then
      access_level="sandbox"
      access_msg="app folder"
    else
      access_level="dropbox"
      access_msg="full dropbox"
    fi

    echo -ne "\n > app key is $appkey, app secret is $appsecret and access level is $access_msg. looks ok? [y/n]: "
    read answer
    if [[ $answer == "y" ]]; then
      break;
    fi

  done

  #token requests
  echo -ne "\n > token request... "
  $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_signature_method=plaintext&oauth_signature=$appsecret%26&oauth_timestamp=$(utime)&oauth_nonce=$random" "$api_request_token_url" 2> /dev/null
  check_http_response
  oauth_token_secret=$(sed -n 's/oauth_token_secret=\([a-z a-z 0-9]*\).*/\1/p' "$response_file")
  oauth_token=$(sed -n 's/.*oauth_token=\([a-z a-z 0-9]*\)/\1/p' "$response_file")

  if [[ $oauth_token != "" && $oauth_token_secret != "" ]]; then
    echo -ne "ok\n"
  else
    echo -ne " failed\n\n please, check your app key and secret...\n\n"
    remove_temp_files
    exit 1
  fi

  while (true); do

    #user auth
    echo -ne "\n please open the following url in your browser, and allow dropbox uploader\n"
    echo -ne " to access your dropbox folder:\n\n --> ${api_user_auth_url}?oauth_token=$oauth_token\n"
    echo -ne "\npress enter when done...\n"
    read

    #api_access_token_url
    echo -ne " > access token request... "
    $curl_bin $curl_accept_certificates -s --show-error --globoff -i -o "$response_file" --data "oauth_consumer_key=$appkey&oauth_token=$oauth_token&oauth_signature_method=plaintext&oauth_signature=$appsecret%26$oauth_token_secret&oauth_timestamp=$(utime)&oauth_nonce=$random" "$api_access_token_url" 2> /dev/null
    check_http_response
    oauth_access_token_secret=$(sed -n 's/oauth_token_secret=\([a-z a-z 0-9]*\)&.*/\1/p' "$response_file")
    oauth_access_token=$(sed -n 's/.*oauth_token=\([a-z a-z 0-9]*\)&.*/\1/p' "$response_file")
    oauth_access_uid=$(sed -n 's/.*uid=\([0-9]*\)/\1/p' "$response_file")

    if [[ $oauth_access_token != "" && $oauth_access_token_secret != "" && $oauth_access_uid != "" ]]; then
      echo -ne "ok\n"

      #saving data in new format, compatible with source command.
      echo "appkey=$appkey" > "$config_file"
      echo "appsecret=$appsecret" >> "$config_file"
      echo "access_level=$access_level" >> "$config_file"
      echo "oauth_access_token=$oauth_access_token" >> "$config_file"
      echo "oauth_access_token_secret=$oauth_access_token_secret" >> "$config_file"

      echo -ne "\n setup completed!\n"
      break
    else
      print " failed\n"
      error_status=1
    fi

  done;

  remove_temp_files
  exit $error_status
fi

################
#### start ####
################

command=${@:$optind:1}
arg1=${@:$optind+1:1}
arg2=${@:$optind+2:1}

let argnum=$#-$optind

#checking params values
case $command in

  upload)

    if [[ $argnum -lt 2 ]]; then
      usage
    fi

    file_dst=${@:$#:1}

    for (( i=$optind+1; i<$#; i++ )); do
      file_src=${@:$i:1}
      db_upload "$file_src" "/$file_dst"
    done

  ;;

  download)

    if [[ $argnum -lt 1 ]]; then
      usage
    fi

    file_src=$arg1
    file_dst=$arg2

    db_download "/$file_src" "$file_dst"

  ;;

  share)

    if [[ $argnum -lt 1 ]]; then
      usage
    fi

    file_dst=$arg1

    db_share "/$file_dst"

  ;;

  info)

    db_account_info

  ;;

  delete|remove)

    if [[ $argnum -lt 1 ]]; then
      usage
    fi

    file_dst=$arg1

    db_delete "/$file_dst"

  ;;

  move|rename)

    if [[ $argnum -lt 2 ]]; then
      usage
    fi

    file_src=$arg1
    file_dst=$arg2

    db_move "/$file_src" "/$file_dst"

  ;;

  copy)

    if [[ $argnum -lt 2 ]]; then
      usage
    fi

    file_src=$arg1
    file_dst=$arg2

    db_copy "/$file_src" "/$file_dst"

  ;;

  mkdir)

    if [[ $argnum -lt 1 ]]; then
      usage
    fi

    dir_dst=$arg1

    db_mkdir "/$dir_dst"

  ;;

  list)

    dir_dst=$arg1

    #checking dir_dst
    if [[ $dir_dst == "" ]]; then
      dir_dst="/"
    fi

    db_list "/$dir_dst"

  ;;

  unlink)

    db_unlink

  ;;

  *)

    if [[ $command != "" ]]; then
      print "error: unknown command: $command\n\n"
      error_status=1
    fi
    usage

  ;;

esac

remove_temp_files
exit $error_status

第一次使用,这个脚本会给你指导,告诉你去哪里获得dropbox的 api key 。

因为只有配置好了 api key ,这样才能授权给脚本应用进入你的dropbox目录

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网