如何编写shell脚本将VPS上的数据备份到Dropbox网盘
短信预约 -IT技能 免费直播动态提醒
本篇内容主要讲解“如何编写shell脚本将VPS上的数据备份到Dropbox网盘”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何编写shell脚本将VPS上的数据备份到Dropbox网盘”吧!
#!/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 fileCONFIG_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 requestsCHUNK_SIZE=4#Curl location#If not set, curl will be searched into the $PATH#CURL_BIN="/usr/bin/curl"#Default valuesTMP_DIR="/tmp"DEBUG=0QUIET=0SHOW_PROGRESSBAR=0SKIP_EXISTING_FILES=0ERROR_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 shellif [ -z "$BASH_VERSION" ]; then echo -e "Error: this script requires the BASH shell!" exit 1fishopt -s nullglob #Bash allows filename patterns which match no files to expand to a null string, rather than themselvesshopt -s dotglob #Bash includes filenames beginning with a "." in the results of filename expansion#Look for optional config file parameterwhile 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 ;; esacdoneif [[ $DEBUG != 0 ]]; then echo $VERSION set -x RESPONSE_FILE="$TMP_DIR/du_resp_debug"fiif [[ $CURL_BIN == "" ]]; then BIN_DEPS="$BIN_DEPS curl" CURL_BIN="curl"fi#Dependencies checkwhich $BIN_DEPS > /dev/nullif [[ $? != 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 1fi#Check if readlink is installed and supports the -m option#It's not necessary, so no problem if it's not installedwhich readlink > /dev/nullif [[ $? == 0 && $(readlink -m "//test" 2> /dev/null) == "/test" ]]; then HAVE_READLINK=1else HAVE_READLINK=0fi#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/nullif [[ $? == 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 variablefunction print{ if [[ $QUIET == 0 ]]; then echo -ne "$1"; fi}#Returns unix timestampfunction utime{ echo $(date +%s)}#Remove temporary filesfunction 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: darwin9function 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}#Usagefunction 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 codefunction 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}#Urlencodefunction 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/ERRfunction 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/dirfunction db_upload{ local class="lazy" data-src=$(normalize_path "$1") local DST=$(normalize_path "$2") #Checking if the file/dir exists if [[ ! -e $class="lazy" data-src && ! -d $class="lazy" data-src ]]; then print " > No such file or directory: $class="lazy" data-src\n" ERROR_STATUS=1 return fi #Checking if the file/dir has read permissions if [[ ! -r $class="lazy" data-src ]]; then print " > Error reading file $class="lazy" data-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 "$class="lazy" data-src") DST="$DST/$filename" fi #It's a directory if [[ -d $class="lazy" data-src ]]; then db_upload_dir "$class="lazy" data-src" "$DST" #It's a file elif [[ -e $class="lazy" data-src ]]; then db_upload_file "$class="lazy" data-src" "$DST" #Unsupported object... else print " > Skipping not regular file \"$class="lazy" data-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 filefunction db_upload_file{ local FILE_class="lazy" data-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_class="lazy" data-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_class="lazy" data-src" "$FILE_DST" else db_simple_upload_file "$FILE_class="lazy" data-src" "$FILE_DST" fi}#Simple file upload#$1 = Local source file#$2 = Remote destination filefunction db_simple_upload_file{ local FILE_class="lazy" data-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_class="lazy" data-src\" to \"$FILE_DST\"... $LINE_CR" $CURL_BIN $CURL_ACCEPT_CERTIFICATES $CURL_PARAMETERS -i --globoff -o "$RESPONSE_FILE" --upload-file "$FILE_class="lazy" data-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 filefunction db_chunked_upload_file{ local FILE_class="lazy" data-src=$(normalize_path "$1") local FILE_DST=$(normalize_path "$2") print " > Uploading \"$FILE_class="lazy" data-src\" to \"$FILE_DST\"" local FILE_SIZE=$(file_size "$FILE_class="lazy" data-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_class="lazy" data-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 dirfunction db_upload_dir{ local DIR_class="lazy" data-src=$(normalize_path "$1") local DIR_DST=$(normalize_path "$2") #Creatig remote directory db_mkdir "$DIR_DST" for file in "$DIR_class="lazy" data-src/"*; do db_upload "$file" "$DIR_DST" done}#Returns the free space on DropBox in bytesfunction 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/dirfunction db_download{ local class="lazy" data-src=$(normalize_path "$1") local DST=$(normalize_path "$2") TYPE=$(db_stat "$class="lazy" data-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 "$class="lazy" data-src") fi local DEST_DIR=$(normalize_path "$DST/$basedir") print " > Downloading \"$class="lazy" data-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 "$class="lazy" data-src/$FILE" "$DEST_DIR/$FILE" else db_download "$class="lazy" data-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 "$class="lazy" data-src") fi #If the destination is a directory, the file will be download into if [[ -d $DST ]]; then DST="$DST/$class="lazy" data-src" fi db_download_file "$class="lazy" data-src" "$DST" #Doesn't exists else print " > No such file or directory: $class="lazy" data-src\n" ERROR_STATUS=1 return fi}#Simple file download#$1 = Remote source file#$2 = Local destination filefunction db_download_file{ local FILE_class="lazy" data-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_class="lazy" data-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_class="lazy" data-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 infofunction 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 unlinkfunction 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 deletefunction 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 locationfunction db_move{ local FILE_class="lazy" data-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_class="lazy" data-src") FILE_DST=$(normalize_path "$FILE_DST/$filename") fi print " > Moving \"$FILE_class="lazy" data-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_class="lazy" data-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 locationfunction db_copy{ local FILE_class="lazy" data-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_class="lazy" data-src") FILE_DST=$(normalize_path "$FILE_DST/$filename") fi print " > Copying \"$FILE_class="lazy" data-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_class="lazy" data-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 createfunction 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 directoryfunction 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 filefunction 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 FILEif [[ -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_STATUSfi#################### START ####################COMMAND=${@:$OPTIND:1}ARG1=${@:$OPTIND+1:1}ARG2=${@:$OPTIND+2:1}let argnum=$#-$OPTIND#CHECKING PARAMS VALUEScase $COMMAND in upload) if [[ $argnum -lt 2 ]]; then usage fi FILE_DST=${@:$#:1} for (( i=$OPTIND+1; i<$#; i++ )); do FILE_class="lazy" data-src=${@:$i:1} db_upload "$FILE_class="lazy" data-src" "/$FILE_DST" done ;; download) if [[ $argnum -lt 1 ]]; then usage fi FILE_class="lazy" data-src=$ARG1 FILE_DST=$ARG2 db_download "/$FILE_class="lazy" data-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_class="lazy" data-src=$ARG1 FILE_DST=$ARG2 db_move "/$FILE_class="lazy" data-src" "/$FILE_DST" ;; copy) if [[ $argnum -lt 2 ]]; then usage fi FILE_class="lazy" data-src=$ARG1 FILE_DST=$ARG2 db_copy "/$FILE_class="lazy" data-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 ;;esacremove_temp_filesexit $ERROR_STATUS
到此,相信大家对“如何编写shell脚本将VPS上的数据备份到Dropbox网盘”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341