45fan.com - 路饭网

搜索: 您的位置主页 > 电脑频道 > 电脑教程 > 阅读资讯:shell脚本备份VPS数据到Dropbox网盘的实例

shell脚本备份VPS数据到Dropbox网盘的实例

2015-07-23 07:40:03 来源:www.45fan.com 【

shell脚本备份VPS数据到Dropbox网盘的实例

看到有人用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目录


本文地址:http://www.45fan.com/dnjc/15387.html
Tags: shell 脚本 编写
编辑:路饭网
关于我们 | 联系我们 | 友情链接 | 网站地图 | Sitemap | App | 返回顶部