编写shell脚本将VPS上的数据备份到Dropbox网盘的方法
程序员文章站
2023-02-13 23:10:11
看到有人用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目录