shell脚本(傻瓜式处理文件到指定分类)

前言

  每一到两周,我大概会新增十多个甚至更多的资料文件,都是些最近遇到的一些问题的总结或者相关技术文档,但是资料都是在公司电脑上,拷贝到自己电脑上后,又得一个个去找一个这个应该放到哪个分类,个人感觉很麻烦。

傻瓜式处理文件脚本

  为了解决困扰俺的这个问题,我想到了一个比较笨的解决办法,用脚本解决,但是这样就做出了一些牺牲,比如

  1. 脚本里规定了文件夹分类的命名方式为nn##为前缀,否则就不把它当作分类,n是数字0-9,例如我的:
00##linux
           00##fedora
           00##ubuntu
           00##工具
01##windows
02##mine
03##电子书
  1. 同时也规定了新增文件或者文件夹命名要以将要移到哪个文件夹分类名为前缀,比如新增一个文件automake.doc,他属于linux下的工具,那么命名时就以 工具aotumake.doc 如果发生冲突,比如在windows下也有工具这个文件夹分类,那么会提示你选择一个。

这是傻瓜式的处理啦,我也考虑过智能的,但是智能的可能会导致很多冲突,经常会提醒你选一个,那样反而麻烦,或许有更好的智能处理,希望大家提示下我,因为我对智能匹配不怎么了解,现在是否有这方面相关的开源代码也不知道

先把脚本列出来啦,大家多多指点下我啦,脚本中哪些处理的不当等都可以留言。

我用的环境是: 虚拟机fedora里运行程序来处理windows的磁盘

    #!/bin/bash
    #限制: 分类的文件夹必须是两位数字然后##开头,不能多也不能少,如00##linux
    #禁止文件名中有"、@,这些内部在处理包含空格的文件时要用到

    unset cmd_cnt
    unset cmds
    unset err_cnt
    unset err_log
    unset dst_path
    unset dirs

    bin_path="`which $0`"
    DEFAULT_CACHE_FILE="${bin_path%/*}/.cache.log"
    DEFAULT_ERR_INFO_FILE="${bin_path%/*}/.error.log"
    DEFAULT_RIG_INFO_FILE="${bin_path%/*}/.right.log"
    DEFAULT_TMP_FILE="${bin_path%/*}/.tmp.log"

    cmd_cnt=0
    err_cnt=0

    HELPFLAG=0
    EXITFLAG=0
    CACHEFLAG=0
    TMPFLAG=0
    CLEANFLAG=0
    UPDATEFLAG=0
    DISPLAY=0

    trap int_handle INT

    int_handle ()
    {
        echo "get int signal"
        rm -f $DEFAULT_ERR_INFO_FILE
        rm -f $DEFAULT_RIG_INFO_FILE
        EXITFLAG=1
        event_handle
    }

    print_help ()
    {
        echo "Usage: $0 help Print help"
        echo "Usage: $0 display Print the current classification of cache"
        echo "Usage: $0 clean Clean the current classification of cache"
        echo "Usage: $0 update dst_path Create or update classification cache by dst_path directory"
        echo "Usage: $0 src_path Autoassign src_path directory with current classification cache"
        echo "Usage: $0 src_path dst_path Autoassign src_path directory with classify directory dst_path and create cache by dst_path,"
        echo " ${0//[a-z/]/ } but premise is current classification of cache is not exist, otherwise, dst_path will be ignored"
    }

    do_update ()
    {
        if [ "$1" != "" ]; then
            [ ! -d "$1" ] && echo "=============>"dst_dir: "$1" is invalid! && return 1
            dst_path="$1"
        else
            if [ -s "$DEFAULT_CACHE_FILE" -a -r "$DEFAULT_CACHE_FILE" ]; then
                dst_path="`head -n 1 $DEFAULT_CACHE_FILE | cut -d '\' -f 2`"
                [ ! -d "$dst_path" ] && echo "=============>"dst_dir: "$dst_path" is invalid! cache file error! do clean first! && return 1
            else
                echo "=============>update maybe $DEFAULT_CACHE_FILE is not exist!"
                echo "=============>you should specify a directory, eg: $0 update dst_dir!"
                return 1
            fi
        fi

        rm -f $DEFAULT_CACHE_FILE
        echo "update..."
        collect_classify_info "$dst_path"
        [ "$?" == 0 ] && create_cache "$dst_path" || return 1
        echo "update ok!"
        return 0
    }

    if_in_records ()
    {
        local arg1
        [ "$cmd_cnt" == 0 ] && return 1
        for i in `seq 0 $(($cmd_cnt-1))`
        do
            arg1=`echo ${cmds[$i]} | cut -d ' ' -f2`
            arg1=${arg1:0:${#arg1}-1}
            echo "$1" | grep -q "^$arg1.*/.*" && return 0
        done
        return 1
    }

    move_record ()
    {
        cmds[cmd_cnt]=mv "$1" "$2"
        let cmd_cnt++
    }

    move_records ()
    {
        local i=0
        local dir dirs
        src=$1

        echo -e "=============>path:$src 
find dir in"
        shift

        dirs=($@)
        for dir in ${dirs[@]}
        do
            echo -e "	[$i] $dir"
            let i++
        done
        read -p "=============>select one: " choice

        if [ "$choice" -ge 0 -a "$choice" -lt $i ]; then
            echo "=============>your choice is $choice ${dirs[$choice]}"
            cmds[cmd_cnt]=mv "$src" "${dirs[$choice]}"
            let cmd_cnt++
        else
            echo "=============>choice $choice wrong!"
            err_record $src
        fi 2> /dev/null
    }

    err_record ()
    {
        err_log[err_cnt]="$1"
        let err_cnt++
    }

    exec_cmd ()
    {
        local cmd
        for cmd in "${cmds[@]}"
        do
            arg1=`echo $cmd | cut -d ' ' -f2`
            arg2=`echo $cmd | cut -d ' ' -f3`
            arg1=${arg1//"/}
            arg2=${arg2//"/}

            opt1=$(basename $arg1)
            opt2=$(basename $arg2)
            lastname=${opt1#${opt2:4}}

            [ "$lastname" == "" ] && echo "$arg1" is invalid! &&
                            echo "=============>mv" "${arg1//@/ }" "${arg2//@/ }"/"${lastname//@/ }" "failed!" 
                            | tee -a $DEFAULT_ERR_INFO_FILE && continue

            mv "${arg1//@/ }" "${arg2//@/ }"/"${lastname//@/ }"
            [ "$?" == 0 ] && echo "=============>mv" "${arg1//@/ }" "${arg2//@/ }"/"${lastname//@/ }" successed! 
                            | tee -a $DEFAULT_RIG_INFO_FILE || echo "=============>mv" "${arg1//@/ }" "${arg2//@/ }"/"${lastname//@/ }" failed!
                            | tee -a $DEFAULT_ERR_INFO_FILE
        done
    }

    print_autoassign_message ()
    {
        local err cmd

        rm -f $DEFAULT_ERR_INFO_FILE
        echo ------------------------error message------------------------
        if [ "$err_cnt" -gt 0 ]; then
            for err in ${err_log[@]}
            do
                echo ${err//@/ } | tee -a $DEFAULT_ERR_INFO_FILE
            done
        fi
        echo -------------------------------------------------------------

        echo ------------------------right message------------------------
        if [ "$cmd_cnt" -gt 0 ]; then
            for cmd in "${cmds[@]}"
            do
                echo move: ${cmd//@/ } #| tee -a $DEFAULT_RIG_INFO_FILE
            done
        fi
        echo -------------------------------------------------------------
    }

    start_autoassign ()
    {
        items=`find "$1"/* 2>>$DEFAULT_TMP_FILE | sed 's/ /@/g' | sed 's/(^.*$)/"1"/g'`
        for item in $items
        do
            if_in_records "$item" && continue
            tmpitem="`eval basename $item`"
            j=0
            for i in `seq 0 $total`
            do
                tmpdir="`eval basename ${dirs[$i]}`"
                echo "$tmpitem" | grep -q "^${tmpdir:4}" && itemdirs[j]=${dirs[$i]} && let j++
            done

            [ $j -eq 0 ] && err_record $item

            [ $j -eq 1 ] && move_record "$item" "${itemdirs[0]}"

            [ $j -gt 1 ] && move_records "$item" "${itemdirs[@]}"
        done 2>>$DEFAULT_TMP_FILE

        [ -s $DEFAULT_TMP_FILE ] && TMPFLAG=1 && return 1 || return 0
    }
        
    collect_classify_info ()
    {
        local i=0
        local dir=
        local err_flag=0

        if [ -s "$DEFAULT_CACHE_FILE" -a -r "$DEFAULT_CACHE_FILE" ]; then
            for dir in `cat $DEFAULT_CACHE_FILE`
            do
                [ "${dir:0:1}" == "\" ] && continue
                echo classify:"$dir"
                dirs[i]="$dir"
                let i++
            done
        else
            for dir in `find "$1"/* -type d -name "[0-9][0-9]##[^0-9]*" 2>/dev/null | sed 's/ /@/g' | sed 's/(^.*$)/"1"/g'`
            do
                echo classify:"$dir"
                dirs[i]="$dir"
                let i++
            done
            CACHEFLAG=1
        fi

        total=$((i-1))
        if [ "$total" -gt 0 ];then
            echo "=============>init success!"
            return 0
        else
            echo "=============>init failed!"
            EXITFLAG=1
            return 1
        fi
    }

    create_cache ()
    {
        local err_flag=0
        if [ "$CACHEFLAG" == 1 ]; then
                echo "\$1" >> $DEFAULT_CACHE_FILE || err_flag=1
                for i in `seq 0 $total`
                do
                    echo "${dirs[$i]}" >> $DEFAULT_CACHE_FILE || err_flag=1
                done
                if [ "$err_flag" == 0 ]; then
                    echo "=============>create cache success!"
                    return 0
                else
                    echo "=============>create cache failed!"
                    return 1
                fi
        fi
        return 0
    }

    parse_argv ()
    {
        dst_path="$2"
        if [ "$2" != "" -a "${2:0:1}" != '/' ]; then
            dst_path="`pwd`/$2"
        fi

        case "$1" in
            help)
                HELPFLAG=1
                EXITFLAG=1
                return 1
            ;;
            display)
                DISPLAY=1
                EXITFLAG=1
                return 1
            ;;
            clean)
                CLEANFLAG=1
                EXITFLAG=1
                return 1
            ;;
            update)
                UPDATEFLAG=1
                EXITFLAG=1
                return 1
            ;;
            *)
                local need_num=0
                if [ -s "$DEFAULT_CACHE_FILE" -a -r "$DEFAULT_CACHE_FILE" ]; then
                    [ ! -e "$1" ] && echo "parse argument file "$1" is not exist" && HELPFLAG=1 && EXITFLAG=1 && return 1
                    dst_path="`head -n 1 $DEFAULT_CACHE_FILE | cut -d '\' -f 2`"
                    [ "$2" != "" ] && echo "read dst_path:$dst_path from cache file, ignore dst_dir:$2"
                    need_num=1
                else
                    [ ! -e "$1" -o ! -e "$2" ] && echo "parse argument failed!" && HELPFLAG=1 && EXITFLAG=1 && return 1
                    need_num=2
                fi
                [ $# -lt "$need_num" ] && HELPFLAG=1 && EXITFLAG=1 && return 1
                return 0
            ;;
        esac
    }

    do_save ()
    {
        if [ ! -e "$1" ]; then
            echo "=============>$1" is not exist
            return 1
        fi

        local do_it=0
        local filename="$2"

        while :;
        do
            if [ -e "$filename" ]; then
                read -p "=============>$2 is exist, Do you want to overwrite it or change filename? Y[y]/C[c]/N[n]" Yn
                if [ "$Yn" == Y -o "$Yn" == y ] ; then
                    do_it=1
                    break
                elif [ "$Yn" == C -o "$Yn" == c ] ; then
                    read -p "input filename ? " filename
                else
                    break
                fi
            else
                do_it=1
                break
            fi
        done

        [ "$do_it" == 1 ] && cp "$1" "$filename" && echo "save $filename successed!" && return 0 || return 1
    }

    autoassign_handle ()
    {
        local RET=0
        if [ "$cmd_cnt" -gt 0 ]; then
            read -p "do move ? Y[y]/N[n] " Yn
            if [ "$Yn" == "Y" -o "$Yn" == "y" ] ; then
                echo "start moving..."
                exec_cmd
                echo "move finished!"
            fi
        else
            echo nothing need to move!
            EXITFLAG=1
            RET=1
        fi

        if [ -s $DEFAULT_ERR_INFO_FILE -a -r $DEFAULT_ERR_INFO_FILE ]; then
            read -p "print error messages ? Y[y]/N[n] " Yn
            if [ "$Yn" == Y -o "$Yn" == y ] ; then
                echo -e "
----------------------error messages----------------------------
"
                cat -n $DEFAULT_ERR_INFO_FILE
                echo -e "
----------------------------------------------------------------
"
            fi
            read -p "save error messages to file ? Y[y]/N[n] " Yn
            if [ "$Yn" == Y -o "$Yn" == y ] ; then
                read -p "input filename ? " filename
                do_save "$DEFAULT_ERR_INFO_FILE" "$filename"
            fi
            rm -f $DEFAULT_ERR_INFO_FILE
        fi

        if [ -s $DEFAULT_RIG_INFO_FILE -a -r $DEFAULT_RIG_INFO_FILE ]; then
            read -p "print moved messages ? Y[y]/N[n] " Yn
            if [ "$Yn" == Y -o "$Yn" == y ] ; then
                echo -e "
-----------------------moved messages---------------------------
"
                cat -n $DEFAULT_RIG_INFO_FILE
                echo -e "
----------------------------------------------------------------
"
            fi
            read -p "save right messages to file ? Y[y]/N[n] " Yn
            if [ "$Yn" == Y -o "$Yn" == y ] ; then
                read -p "input filename ? " filename
                do_save "$DEFAULT_RIG_INFO_FILE" "$filename"
            fi
            rm -f $DEFAULT_RIG_INFO_FILE
        fi
        return $RET
    }
        
    event_handle ()
    {
        echo "start event handle..."
        if [ "$HELPFLAG" == 1 ]; then
            HELPFLAG=0
            echo "===============start================"
            print_help
            echo "================end================="
        fi

        if [ "$DISPLAY" == 1 ]; then
            echo "===============start================"
            DISPLAY=0
            if [ -s "$DEFAULT_CACHE_FILE" -a -r "$DEFAULT_CACHE_FILE" ]; then
                tail -n +2 $DEFAULT_CACHE_FILE
            else
                echo "=============>display maybe $DEFAULT_CACHE_FILE is not exist!"
            fi
            echo "================end================="
        fi

        if [ "$TMPFLAG" == 1 ]; then
            TMPFLAG=0
            echo "================error!!!============="
            cat $DEFAULT_TMP_FILE
            echo "====================================="
            rm -f "$DEFAULT_TMP_FILE"
            EXITFLAG=1
        fi

        if [ "$CLEANFLAG" == 1 ]; then
            CLEANFLAG=0
            rm -f $DEFAULT_CACHE_FILE
            echo "clean ok!"
        fi

        if [ "$UPDATEFLAG" == 1 ]; then
            UPDATEFLAG=0
            do_update "$dst_path"
        fi

        echo "event handle finished!"
        if [ "$EXITFLAG" == 1 ]; then
            exit
        fi
    }

    echo "start parse. argument: $@"
    parse_argv "$@" || event_handle
    echo "parse finished!"

    echo "start collect classify info from $dst_path"
    collect_classify_info "$dst_path" || event_handle
    echo "collect finished!"

    create_cache "$dst_path"

    echo "start autoassign from ${1}"
    start_autoassign "$1" || event_handle
    echo "autoassign finished!"

    print_autoassign_message#

    echo "start autoassign handle"
    autoassign_handle
    echo "autoassign handle 

体会

 使用一段时间后,发现这种方式不太可行,除非你能接受所有文件及文件夹命令按上文所要求那样,之所以还保留这篇文章,也是期望某个高人能够有更好的想法提出。

完!
2012年12月

原文地址:https://www.cnblogs.com/rongpmcu/p/7662168.html