首页 > 代码库 > (转载)基于Bash命令行的百度云上传下载工具

(转载)基于Bash命令行的百度云上传下载工具

原文链接:http://hi.baidu.com/meoow/item/aef5814bbd5be3e1bcf451e9

 

这是我根据百度云PCS的API写的一个基于bash的命令行工具,

使用了curl, awk, sed, xxd, bash,没有使用任何其他的语言解释器做辅助

目前,上传下载,文件列表,文件信息,创建文件夹,删除文件都没问题

复制和移动总是返回参数错误,实在找不出来哪里跟API不一致了,暂时放弃。

另外离线下载相关的API也都添加了,但是因为现在百度云不能申请,我是用的是bypy的client_id,

不知道它的离线下载相关权限没有抑或其他问题,添加任务返回500。

不过总的来说基本上对于一般使用百毒云是够用了

#!/bin/bash# Baidu Yun Command Line Interface# Depends: bash, curl, grep, awk, sed, xxd# (Thay are basicly builtin tools of any *nix system.)# Additionally, fastupload depends: head, wc, md5sum or md5, cksum# (Which are also builtin tools)# issues:# move, copy and all offline-download related commnads do not work# the latters are probably prohibited by baidu# or the current bypy client has no permission for them.#### Variables ##### This three to be changed to your own code #TOKEN=00.00000000000000000000000000000000.0000000.0000000000.000000000000000000# baidu has prohibited registering new client id# the client_id is borrowed from bypy (Another great baidu yun cli tool written in python)CLIENT_ID=q8WE4EpCsau1oS0MplgMKNBn# you should at least login pan.baidu.com from browser once,# then you can obtain the BDUSS code in the Cookie.BDUSS=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;########################################pathprefix=/apps/bypy/ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8ACCPET_LANGUAGE=zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3ACCPET_ENCODING=identityCACHE_CONTROL=no-cacheCONNECTION=keep-aliveDNT=1HOST=pcs.baidu.comORIGIN=http://pan.baidu.comPRAGMA=no-cacheREFERER=http://pan.baidu.com/disk/homeUA=Mozilla/5.0 (X11; Linux; rv:5.0) Gecko/5.0 Firefox/5.0CURL_DEFAULT_ARGS=(    -H "Accept: $ACCEPT"    -H "Accept-Language: $ACCPET_LANGUAGE"    -H "Cache-Control: $CACHE_CONTROL"    -H "Connection: $CONNECTION"    -H "DNT: $DNT"    -H "Host: $HOST"    -H "Origin: $ORIGIN"    -H "Pragma: $PRAGMA"    -H "Referer: $REFERER"    -H "Accept-Encoding: $ACCPET_ENCODING"    -A "$UA")######################## Defining functions ##### encoding character to %xx formaturlencode() {    local length="${#1}"    local c    for (( i = 0; i < length; i++ )); do    c="${1:i:1}"    case $c in    testa-zA-Z0-9.~_-) printf "%s" "$c" ;;    *) printf "%s" "$c" | xxd -p -c1 | while read x;do printf "%%%s" "$x";done    esacdone}# for *basic* regexp syntax surrounded by double quotesregexescape() {local len="${#1}"local cfor(( i=0;i<len;i++ ));doc="${1:i:1}"case "$c" intest*\\/^$|]|[|-)    printf "\\\\%s" "$c";;*)    printf "%s" "$c"    esacdone}# baidu yun authorizeauth() {local codeecho "http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=oob&scope=basic%20netdisk&"code=$(curl -Ls "http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=oob&scope=basic%20netdisk&" -H "Cookie: BDUSS=$BDUSS"|grep -o readonly value="http://www.mamicode.com/[^"]*"|grep -o [[:xdigit:]]\{32\})curl -Ls "https://bypy-tianze.rhcloud.com/auth?code=$code&redirect_uri=oob&"|grep -o "[^"]\{1,\}":"[^"]\{1,\}"|sed -n /access_token/s/^.*:"\([[:xdigit:].-]\{1,\}\)"$/\1/p}# print helpusage() {cat <<_EOF_    $0 <command > [arguments...]    Command:    auth    upload    <FILE > [PATH] [overwrite|newcopy]    fastupload    <FILE > [PATH] [overwrite|newcopy]    download  <PATH > [SAVEDIR] [SAVENAME]    list      [PATH]    mkdir     <PATH >    meta      <PATH >    move      <FROM > <TO>    copy      <FROM > <TO>    delete    <PATH >    search    <PATH > <WORD>    add       <URI > [PATH]    query     <TASKID >    tasks    cancel    <TASKID >    trash    retore    <FILEID >    _EOF_}# JSON pretty printertokenize () {    local GREP    local ESCAPE    local CHAR    GREP=egrep -ao    ESCAPE=(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})    CHAR=[^[:cntrl:]"\\]    local STRING="\"$CHAR*($ESCAPE$CHAR*)*\""    local NUMBER=-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?    local KEYWORD=null|false|true    local SPACE=[[:space:]]+    $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"}printw() {    local n="$1"    if test[ "$n" =~ [1-9][0-9]* ];then        :    else        return 0    fi    for((i=0;i<n;i++));do    printf " "done}pprint() {local indent=0local value=0while read x; do    case "$x" in    {|[)        if ((value));then            printf " "            value=0        else            printw $indent        fi        ((indent++))        printf "%s\n" "$x"    ;;    }|])        value=0        ((indent > 0 && indent--))        echo        printw $indent        printf "%s" "$x"    ;;    ,)        value=0        echo    ;;    :)        value=1        printf "%s" "$x"    ;;    *)        if ((value));then            value=0            printf " "        else            printw $indent        fi        printf "%s" "$x"    ;;    esacdone}# compact json output (parse output from pprint only)compact() {# arguments: -f -t -b -m -s# -f no fs_id# -t no ctime and mtime# -b no brackets# -m no md5# -s no size#default is to remove double quoteslocal sedcmd=s/"\([^"]*\)"/\1/g;while getopts :ftbms arg;do    case "$arg" in    f)        sedcmd="$sedcmd"‘/^ *fs_id/d;    ;;    t)        sedcmd="$sedcmd"‘/^ *ctime/d;/^ *mtime/d;    ;;    m)        sedcmd="$sedcmd"‘/^ *md5:/d;    ;;    s)        sedcmd="$sedcmd"‘/^ *size:/d;    ;;    b) sedcmd="$sedcmd"‘/^ *{/d;s/^ *}$//;/^ *\[$/d;/^ *\]/d;s/: \[$/:/;    ;;    esacdonesed "$sedcmd"}autounit() {awk -v G=$((1024**3)) -v M=$((1024**2)) -v K=1024 {    if($0~/^ *"?size"?: [[:digit:]]{1,}/){        if($2> =G){            size=sprintf("%0.1fG",$2/G)        } else if($2> =M){            size=sprintf("%0.1fM",$2/M)        } else if($2> =K){            size=sprintf("%0.1fK",$2/K)        } else {            size=$2        }        sub($2,size)    }    print}}crc32() {cksum -o3 < "$1" |while read x y;do    echo $x    breakdone}if type -t md5sum > /dev/null ;thenMD5=md5sum -belseMD5=md5fimd5() {MD5 < "$1" |while read x y;do    echo "$x"    breakdone}md5_256k() {head -c262144 "$1" | MD5 |while read x y;do    echo "$x"    breakdone}size() {wc -c "$1"|while read x y;do    echo "$x"    breakdone}############################################ Parse command line arguments ####case "$1" inauth) authexit 0;;u|upload)method=uploadshiftif test[ -z "$1" ];then    echo "$0 upload <FILE > [PATH] [overwrite|newcopy]" >&2    exit 1fifilepath="$1"filename="$(basename "$filepath")"shiftpath="${1:-/}/$filename"shiftondup="${1:-overwrite}";;f|fastupload)method=rapiduploadshiftif test[ -z "$1" ];then    echo "$0 upload <FILE > [PATH] [overwrite|newcopy]" >&2    exit 1fifilepath="$1"filename="$(basename "$filepath")"shiftpath="${1:-/}/$filename"shiftondup="${1:-overwrite}";;d|download)method=downloadshiftif test[ -z "$1" ];then    echo "$0 download <PATH > [SAVEDIR] [SAVENAME]" >&2    exit 1fipath="$1"shiftsavedir="${1:-.}"shiftsavename="${1:-$(basename "$path")}"savefile="$savedir/$savename";;mkdir)req=POSTmethod=mkdirshiftif test[ -z "$1" ];then    echo "$0 mkdir <PATH > " >&2    exit 1fipath="$1";;meta)req=GETmethod=metashiftif test[ -z "$1" ];then    echo "$0 meta <PATH > " >&2    exit 1fipath="$1";;l|list)method=listshiftpath="${1:-/}";;m|move)method=moveshiftfrom="$1"shiftto="$1"if test[ -z "$from" || -z "$to" ];then    echo "$0 move <FROM > <TO> " >&2    exit 1fi;;c|copy)method=copyshiftfrom="$1"shiftto="$1"if test[ -z "$from" || -z "$to" ];then    echo "$0 copy <FROM > <TO> " >&2    exit 1fi;;s|search)method=searchshiftpath="$1"shiftwd="$1"if test[ -z "$path" || -z "$wd" ];then    echo "$0 search <PATH > <WORD> " >&2    exit 1fi;;del|delete)method=deleteif test[ -z "$1" ];then    echo "$0 delete <PATH > " >&2    exit 1fishiftpath="$1";;add)method=add_taskshiftif test[ -z "$1" ];then    echo "$0 add <LINK > " >&2    exit 1filink="$1"shiftpath="$1";;query)method=query_taskshiftif test[ -z "$1" ];then    echo "$0 query <TASKID > " >&2    exit 1fitaskid="$1";;tasks)method=list_task;;cancel)method=cancel_taskshiftif test[ -z "$1" ];then    echo "$0 cancel <TASKID > " >&2    exit 1fitaskid="$1";;trash)method=listrecycle;;restore)method=restoreshiftif test[ -z "$1" ];then    echo "$0 restore <FILEID > " >&2    exit 1fifsid="$1";;h|help)usageexit 0;;*)usageexit 0;;esacpath="$pathprefix""$path"from="$pathprefix""$from"to="$pathprefix""$to"#### determining request type ####case $method ininfo|download|meta|list|search|generate|diff|streaming|listrecycle)req=GET;;upload|delete|createsuperfile|move|copy|rapidupload|add_task|list_task|query_task|cancel_task|restore|mkdir)req=POST;;esac###################################### determining URI #############case $method inupload) uriprefix=https://c.pcs.baidu.com/rest/2.0/pcs/file;;download) uriprefix=https://d.pcs.baidu.com/rest/2.0/pcs/file;;list_task|query_task|cancel_task)uriprefix=https://pcs.baidu.com/rest/2.0/pcs/services/cloud_dl;;*) uriprefix=https://pcs.baidu.com/rest/2.0/pcs/file;;esac###################################### Building URI depends on specific method ####uriprefix="$uriprefix?access_token=$TOKEN&method=$method"case $method inupload)uri="$uriprefix&path=$(urlencode "$path")&ondup=$ondup";;download|mkdir|meta|delete)uri="$uriprefix&path=$(urlencode "$path")";;list)by=name #time name sizeorder=asc #asc descuri="$uriprefix&path=$(urlencode "$path")&by=$by&order=$order";;move|copy)uri="$uriprefix";;search)re=1uri="$uriprefix&path=$(urlencode "$path")&wd=$(urlencode "$wd")&re=$re";;rapidupload)filelength=$(size "$filepath")filemd5=$(md5 "$filepath")fileslicemd5=$(md5_256k "$filepath")filecrc32=$(crc32 "$filepath")uri="$uriprefix&path=$(urlencode "$path")&content-length=$filelength&content-md5=$filemd5&slice-md5=$fileslicemd5&content-crc32=$filecrc32&ondup=$ondup";;add_task)uri="$uriprefix&save_path=$(urlencode "$path")&source_url=$(urlencode "$link")";;query_task)optype=1uri="$uriprefix&task_ids=$taskid&op_type=$optype";;list_task)start=0limit=20asc=0 #0 1task_info=1 #1 0uri="$uriprefix&start=$start&limit=$limit&asc=$asc&need_task_info=$task_info";;cancel_task)uri="$uriprefix&task_id=$taskid";;listrecycle)uri="$uriprefix&start=0";;restore)uri="$uriprefix&fs_id=$fsid";;esac######################################## Building arguments for CURL ##curlopts=(-X$req"${CURL_DEFAULT_ARGS[@]}")case $method inupload)curlopts=("${curlopts[@]}" -F file=@"$filepath" "$uri");;download)curlopts=("${curlopts[@]}" -o "$savefile" "$uri");;delete|add_task|list_task|query_task|cancel_task|restore|mkdir|rapidupload)curlopts=(    "${curlopts[@]}"    -H "Content-Length: 0"    -Ls "$uri");;move|copy)curlopts=(    "${curlopts[@]}"    -H "Content-Type: application/json"    --data param="{\"list\":[{\"from\":\"$from\",\"to\":\"$to\"}]}"    -Ls "$uri");;*)curlopts=("${curlopts[@]}" -Ls "$uri");;esac#################################### Start the operation #### echo "${curlopts[@]}"; exitcase $method indownload)curl "${curlopts[@]}";;*)curl "${curlopts[@]}"|tokenize|pprint|sed /^ *"path": /s/^\( *"path": "\)‘"$(regexescape "$pathprefix")"‘\(.*"\)$/\1\2/|compact -ftbm | autounit;;esac##########################

 

使用,假设保存成文件名bdcurl的执行文件:
如果想不用浏览器,而是直接在命令行授权给bypy来使用的话,需要在浏览器里登录 过百毒云,然后在cookie里找到BDUSS(可以用firebug,或者使用sqlite打开浏览器的数据库也能找到),把内容复制到脚本开头的 BDUSS变量里(这个有效期比较长,所以基本只复制一次就可以了,以后token过期后重新认证时可以省略这步),
bdcurl auth
等一小会就会输出token id,把这个段字符串复制到脚本开头的TOKEN变量里,然后就可以使用了。

如果不方便获取BDUSS,就需要把终端输出的网址粘贴到浏览器里获取一个code,然后把code替换
https://bypy-tianze.rhcloud.com/auth?code=$code&redirect_uri=oob&
里面$code的部分,获得最后的access_token放到脚本开始的TOKEN变量里。
然后命令行运行:
bdcurl h 看帮助


bdcurl u file1 down #上传文件到down文件夹
bdcurl f file1 down #快速上传文件(只向服务器查询校验信息,如果百度云上有相同的文件,则直接在建立该文件,不需上传,如果返回error_code,则百毒云上没有相同文件,需要使用bdcurl u上传文件)
bdcurl d down/file1 # 下载指定路径的文件
bdcurl del down/file1 # 删除指定路径的文件
bdcurl l down # 列出 down目录下的所有文件

暂时不支持批量上传下载,毕竟百毒本身没有这样的API,所谓批量得在客户端实现,但是bash来实现相对会麻烦很多,因为没有很好的解析json的方法,如果使用python,perl之类的辅助解析,那就不如干脆直接用python或perl写了。

 

另外输出结果使用一个compact函数对其做一定程度的简化,其简化程度可通过参数指定,脚本里默认(compact -ftbm, 倒数第四行)使用最大程度简化(如,去除花括号和方括号,去除fs_id,md5校验码,size文件大小,mtime和ctime创建/修改时间 等项目,如果传递参数里去掉-s则会保留size项),可以自行参看脚本里定义compact函数接收参数的说明,选择你合适的输出简化程度

(转载)基于Bash命令行的百度云上传下载工具