linux/mac下命令行rm回收站--rmtrash


Linux、mac的命令行下沒有回收站功能,很多時候手一抖就把重要文件給 rm -fr * 了,雖然linux下有可能通過lost +found/debugfs找回,但難度也比較大,不能保證一定能夠找回。人總是會犯錯,本人工作這幾年也犯過3次rm -fr刪除后后悔的錯誤,與其后悔不如防范於未然,像桌面操作系統(windows、mac os、Ubuntu)一樣加個回收站機制就可以了,經過幾天的努力終於實現了,放到github上了,歡迎使用。

 

源碼地址:https://github.com/LaiJingli/rmtrash

rmtrash 是linux和mac下命令行版本rm的回收站,安裝后對用戶透明,符合正常使用rm的習慣,有了他再也不怕rm時候手顫抖了。
rmtrash stands for "rm trash" which acts just like the system built-in rm command,and just moves the file to the trash for recovery when needed. 

提醒:rmtrash主要用於防止人為誤刪除操作,回收站本身不能替代系統正常的數據備份操作,數據備份依然非常重要。

 

主要參考了如下2篇文章,向作者表示感謝:

源碼地址:https://github.com/LaiJingli/rmtrash

回收站功能在 Linux 中的實現: http://www.ibm.com/developerworks/cn/linux/1410_licy_linuxtrash

Bash Getopts - 讓你的腳本支持命令行參數: http://linux.cn/article-3204-1.html

原文地址: http://blog.csdn.net/xuyaqun/article/details/44306055

源碼如下:

#!/bin/bash
### rmtrash,rm command line recycle bin for linux and mac osx.
### rmtrash 是linux和mac下命令行版本rm的回收站,安裝后對用戶透明,符合正常使用rm的習慣(支持rm -fr file哦),有了他再也不怕rm時候手顫抖了。
### rmtrash stands for "rm trash" which acts just like the system built-in rm command,and just moves the file to the trash for recovery when needed.
### https://github.com/LaiJingli/rmtrash
### laijingli2006@gmail.com
### 2015-3-9

###trash目錄define
realrm="/bin/rm"
trash_dir=~/.rmtrash/
trash_log=~/.rmtrash.log
###判斷trash目錄是否存在,不存在則創建
if [ ! -d $trash_dir ] ;then
    mkdir -v $trash_dir
fi

###動態修改用戶shell中的alias配置
os_type=`uname`
shell_path=$SHELL
shell_type=`echo $SHELL|awk -F/ '{print $NF}'`
alias_file=~/.${shell_type}rc
alias_rm=`cat $alias_file|grep ^"alias rm="`
return_value=$?
#echo return_value: $return_value
#echo alias_rm: $alias_rm
###如果不存在rm alias,則生成
if [[ $return_value -ne 0 ]] ;then
    echo first time to run rmtrash
    echo "alias rm=/bin/rmtrash.sh" >>$alias_file && source $alias_file
###如果存在rm alias,且不是指向rmtrash的,則注釋掉,區分linux 和mac
elif [[ "$alias_rm" != "alias rm=/bin/rmtrash.sh" ]];then
    echo already has alias rm,and must commit out
    if [[ $os_type == Darwin ]];then
        sed -i .bak 's/^alias\ rm=/#alias\ rm=/g' $alias_file && \
        echo "alias rm=/bin/rmtrash.sh" >>$alias_file && \
        source $alias_file
    elif [[ $os_type == Linux ]];then
        sed -i.bak 's/^alias\ rm=/#alias\ rm=/g' $alias_file && \
        echo "alias rm=/bin/rmtrash.sh" >>$alias_file && \
        source $alias_file
    fi
fi

####function define
###usage function
rm_usage () {
    cat <<EOF
Usage1: `basename $0` file1 [file2] [dir3] [....] delete the files or dirs,and mv them to the rmtrash recycle bin
Usage2: rm         file1 [file2] [dir3] [....] delete the files or dirs,and mv them to the rmtrash recycle bin
        rm is alias to `basename $0`.
options:
    -f  mv one or more files to the rmtrash recycle bin
    -r  mv one or more files to the rmtrash recycle bin
    -fr mv one or more files to the rmtrash recycle bin
    -rf mv one or more files to the rmtrash recycle bin
    -R  Restore selected files to the originalpath from rmtrash recycle bin
    -l  list the contens of rmtrash recycle bin
    -i  show detailed log of the deleted file history
    -d  delete one or more files by user's input file name from the trash
    -e  empty the rmtrash recycle bin
    -h  display this help menu
EOF
}


###rm mv function
rm_mv () {
    echo ----------------------------
    now=`date +%Y%m%d_%H:%M:%S`
    dupfix=.`date +%Y%m%d%H%M%S`
    ###將用戶輸入的文件循環mv到trash中
    ###for file in $file_list ;do
        #echo $file
        ###提取用戶輸入參數的文件名、目錄名,拼出絕對路徑
        file_name=`basename $file`
        file_dir=$(cd `dirname $file`;pwd)
        file_fullpath=$file_dir/$file_name
        ###判斷要刪除的文件或者目錄大小是否超過2G
        #echo file_fullpath: $file_fullpath
        #if [[ "$file_fullpath" == "/*" ]];then
        #    echo action deny!
        #else
        ####判斷即將刪除的文件在trash目錄里是否已存在
        if [[ `ls $trash_dir|grep ^${file_name}$` ]];then
            ##已存在,文件名重復,需要rename,想原始名的基礎上加后綴
            trash_dest_path=$trash_dir$file_name$dupfix
            echo trash目錄里已存在$file_name,需要rename $file_name$dupfix
        else
            ##不重名,直接按原始文件名保存
            trash_dest_path=$trash_dir$file_name
        fi

        ####判斷如果是要刪除文件是根目錄,則直接提示並拒絕
        if [[ "$file_name" == "/" ]];then
            echo rm拒絕執行刪除根目錄操作,否則系統就掛了,你就悲劇了,請檢查...
        else
            ###mv成功記錄log,記錄刪除時的文件、目錄的路徑等信息到log,以便恢復數據
            mv $file_fullpath $trash_dest_path && \
            echo $now `date +%s` `whoami` moved from $file_fullpath to $trash_dest_path >> $trash_log && \
            echo -e "\033[31m\033[05m $file is deleted from $file_fullpath\033[0m"
            #cat $trash_log
        fi

        #fi
    ###done
}

###rm list function
rm_list () {
    echo ----------------------------
    echo list trash_dir contents:
    ls $trash_dir
}


###rm restore function
rm_restore () {
    echo ----------------------------
    echo -en "請選擇要恢復的文件名(多個文件中間空格分隔,取消ctl+c):"
    read reply
    for file in $reply ;do
        ###判斷原始位置的是否有同名文件存在
        originalpath=`cat $trash_log|grep /$file$|awk  '{print $5}'`
        if [[ `ls $originalpath` ]];then
            echo -en "originalpath:$originalpath already exists. continue overwrite or not(y/n):"
            read ack
            if   [[ $ack == y ]];then
                echo restore:
            elif [[ $ack == n ]];then
                echo bye && exit
            else
                echo 輸入非法 && exit
            fi
        fi
        ###
        mv $trash_dir$file  $originalpath && \
        ###linux和mac下sed的用法有細微差別,故需通過操作系統類型進行選擇對應的sed格式
        if [[ $os_type == Darwin ]];then
            sed -i .bak "/\/$file$/d" $trash_log
            echo os_type=Darwin
        elif [[ $os_type == Linux ]];then
            sed -i.bak "/\/$file$/d" $trash_log
            echo os_type=Linux
        fi && \
        echo -e  "\033[32m\033[05m$file restore ok to originalpath=$originalpath\033[0m"
    done
}

### rm show delete log function
rm_infolog () {
    echo ----------------------------
    echo detailed deleted file log:
    cat $trash_log
}


###rm empty trash function
rm_empty () {
    echo ----------------------------
    echo -en "empty trash,all backups in trash will be deleted, continue or not(y/n):"
    read ack
    if   [[ $ack == y ]];then
        echo begin to empty trash:
    elif [[ $ack == n ]];then
        echo bye && exit
    else
        echo 輸入非法 && exit
    fi
    /bin/rm -fr ${trash_dir}* && \
    echo >$trash_log && \
    echo -e "\033[31m\033[05m The trash bin has been emptyed\033[0m"
}

###rm delete function
rm_delete () {
    echo ----------------------------
    echo -en "請選擇trash中要刪除的文件名(多個文件中間空格分隔,取消ctl+c):"
    read reply
        for file in $reply ;do
            ###if file exist then delete it from trash
            if [[ `ls ${trash_dir}$file` ]];then
                /bin/rm -fr ${trash_dir}$file && \
                ###linux和mac下sed的用法有細微差別,故需通過操作系統類型進行選擇對應的sed格式
                if [[ $os_type == Darwin ]];then
                    sed -i .bak "/\/$file$/d" $trash_log
                    echo os_type=Darwin
                elif [[ $os_type == Linux ]];then
                    sed -i.bak "/\/$file$/d" $trash_log
                    echo os_type=Linux
                fi && \
                    echo -e  "\033[32m\033[05m$file  is deleted from trash ${trash_dir}$file \033[0m"
            else
                echo $file is not exist in $trash_dir
            fi
        done
}

###清空回收站中30天之前執行rm刪除過的文件
rm_delete_by_30_days () {
    rm_mv_30_days_ago_timestamp=$1
    ###30*24*3600=2592000
    #30_days_by_seconds=2592000
    #cat $trash_log|awk 'BEGIN{30_days_by_seconds=2592000}{if()}'
    awk   'END{
        print 時間差:$2-2592000
        {if ($2-2592000>100) print dayu}
    }
    ' $trash_log
}

###跨分區的問題

#####主程序開始
###參數個數為0,輸出help
if [ $# -eq 0 ] ;then rm_usage ;fi
###根據用戶輸入選項執行相應動作
###通過非顯示的方式(加入fr選項,但在case里不做匹配操作,遇到含-fr/-rf/-f/-r時直接刪除)支持很多用戶的使用習慣rm -fr file,rm -rf file
while getopts lRiecdhfr option ;do
case "$option" in
        l) rm_list;;
        R) rm_list
           rm_restore;;
        i) rm_infolog;;
        h) rm_usage;;
        e) rm_empty;;
        c) rm_delete_by_30_days;;
        d) rm_list
           rm_delete;;
        \?)rm_usage
           exit 1;;
    esac
done
shift $((OPTIND-1))

###將文件名的參數依次傳遞給rm_mv函數
while [ $# -ne 0 ];do
    file=$1
    echo file=$file
    rm_mv
    shift
done
rmtrash


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM