1. 程式人生 > >修改rm命令以避免誤刪

修改rm命令以避免誤刪

問題重現

是否碰到過如下情況:

  • 寫了一個月的程式碼,沒有做本地提交,手滑來了個rm -rf,然後就沒有然後了。
  • 並沒有注意一個名叫~的資料夾,有一丟丟潔癖的自己習慣性的rm -rf ~,一回車,世界突然安靜。
  • … …

大概的解決方案都是1. 找個地方,2. rm改為mv, 實現rm時把檔案直接mv到這個地方,3. 提供清空回收站/查看回收站檔案/找回誤刪檔案等的操作。

基本需求

基本功能參考windows中的回收站。

  1. 準備一個資料夾,作為垃圾回收站(~/.trash);
  2. 刪除檔案:輕鬆將需要刪除的檔案移動到回收站中,支援資料夾及檔案;支援絕對路徑和相對路徑;支援重名檔案;
  3. 清空回收站:徹底刪除回收站中的檔案及相關資源;
  4. 查看回收站檔案列表:羅列回收站中的檔案,羅列回收站中的檔案的恢復路徑;
  5. 恢復某個檔案:按照恢復路徑及原始檔名稱恢復檔案,該命令應具有自動補全功能;
  6. 重構rm命令,替換其功能;
  7. 提供簡潔的命令訪問;

開發過程

準備全域性變數

export HOME_TRASH_PATH=~/.trash        # 回收站的位置
export TRASH_FILE_LIST=$HOME_TRASH_PATH/.list  # 用於存放原始檔案的路徑
# 建立回收站
if [ ! -d "$HOME_TRASH_PATH" ]; then
   mkdir -p "$HOME_TRASH_PATH
"
fi # 建立回收記錄 if [ ! -f "$TRASH_FILE_LIST" ]; then touch "$TRASH_FILE_LIST" fi

HOME_TRASH_PATH提供了回收站的位置,該功能只在當前使用者環境下生效,故採用~目錄;避免不同使用者使用可能存在的許可權問題。

TRASH_FILE_LIST檔案為文字檔案,用於存放原始檔案的路徑,為恢復檔案提供依據;

刪除檔案

function _trash_delete()
{
   local trash_path=$HOME_TRASH_PATH
   local trash_nanme
   local file_name
   local file_path

   # 應支援多個檔案(夾)一起刪除
for tmp_path in [email protected]; do # 從引數中分離出檔案路徑和檔名 # 利用IFS分割Unix風格的檔案路徑 local old_ifs="$IFS" IFS="/" local file_array=($tmp_path) IFS="$old_ifs" # 陣列中最後一個為檔名, 注意冒號後有個空格 local length=${#file_array[@]} file_name=${file_array[@]: -1} # 指定檔名為"名.時間",避免重名,同時日期可以提供找回的參考 trash_name=$file_name.`date +%Y%m%d-%H:%M:%S` # 獲取第一個字元確認是否為絕對路徑 local _prefix=${tmp_path:0:1} if [ "/" = $_prefix -o "~" = $_prefix ]; then # 絕對路徑只需要去掉檔名就可以獲得路徑,eg:/home/aaa/test_dir file_path=${tmp_path%/$file_name*} else # 相對路徑需要解析出部分路徑後與當前路徑疊加 file_path=${tmp_path%/$file_name*} file_path=`pwd`"/$file_path" fi # 將路徑寫入TRASH_FILE_LIST檔案 echo -e "$trash_name \t\t $file_path" >> $TRASH_FILE_LIST # 將檔案mv到回收站中 mv $tmp_path $HOME_TRASH_PATH/$trash_name done }

顯示回收站中的檔案

# 顯示回收站中垃圾清單
function _trash_list()
{
   # 為輸出加上頭
   echo -e "==== Garbage Lists in $HOME_TRASH_PATH ===="
   _trash_help
   # 列表檔案
   ls -a $HOME_TRASH_PATH
}

顯示回收站中的檔案及路徑

function _trash_path()
{
   # TRASH_FILE_LIST中的檔案結構如下
   # c.c.20180531-20:05:57            /home/aaa/test
   # a.b.20180531-20:06:54            /home/aaa/test/file_path
   # b.c.20180531-20:07:32            /home/aaa/test/file_path
   # b.a.20180531-20:10:51            /home/aaa/test/./b.b
   # 頭
   echo -e "------------bakup name---------------recover path"
   # 輸出檔案及路徑
   cat $TRASH_FILE_LIST
}

恢復檔案

# 找回回收站相應檔案
function _trash_recover()
{
   local rfile_name=    # 需要恢復的檔名
   local file_name=     # 原始檔名
   local file_path=     # 原始檔案路徑
   # 同時支援多個檔案的恢復
   for tmp_path in [email protected];
   do
      # 首先判斷檔案(夾)的存在性,以防mv時出錯
      if [[ ! -d "$HOME_TRASH_PATH/$tmp_path" ]] && [[ ! -f "$HOME_TRASH_PATH/$tmp_path" ]]; then
         echo "no such file : $tmp_path"
         continue
      fi
      rfile_name=$tmp_path
      # 匹配去除(.時間)還原真實檔名
      file_name=${rfile_name%\.*}
      # 通過cat/grep/awk獲取TRASH_FILE_LIST中檔案的原始路徑
      file_path=`cat $TRASH_FILE_LIST | grep "$rfile_name" | awk '{print $2}'`
      # 刪除該記錄,todo
      # 將檔案搬移回原始目錄中
      mv  $HOME_TRASH_PATH/$rfile_name $file_path/$file_name
   done
}

清空回收站

function _trash_clean()
{
   # 以醒目的字型要求再次確認,以免誤刪
   echo -ne "\033[33mClear all trashes in $HOME_TRASH_PATH, Sure?[y/n]\033[0m"
   read confirm
   if [ $confirm == "y" -o $confirm == "Y" ] ;then
      # 呼叫系統rm刪除HOME_TRASH_PATH下的所有檔案
      /bin/rm -rf $HOME_TRASH_PATH/*
      /bin/rm -rf $HOME_TRASH_PATH/.* 2>/dev/null
   fi
}

命令重構

trash()
{
   # 指定對不同引數的解析
   local arg=$1
   shift
   case "$arg" in
      -d)
         _trash_delete [email protected]
         ;;
      -l)
         _trash_list
         ;;
      -r)
         _trash_recover [email protected]
         ;;
      -c)
         _trash_clean
         ;;
      -p)
         _trash_path
         ;;
      -h|*)
         _trash_help
         ;;
   esac

}

alias rm="trash -d"     # 重構rm

# 以下內容修改使用,視具體環境
alias rl="trash -l"     # 這些命令基本在系統中並未用到,所以才如此使用
alias rr="trash -r"
alias rp="trash -p"
alias rc="trash -c"
alias rh="trash -h"

使用說明

function _trash_help()
{
   echo -e "\033[33m----Usage------\033[0m"
   echo -e "\033[33m-1- Use "trash -p" or "rp" to list all garbages and real pathes in $HOME_TRASH_PATH\033[0m"
   echo -e "\033[33m-1- Use "trash -l" or "rl" to list all garbages in $HOME_TRASH_PATH\033[0m"
   echo -e "\033[33m-1- Use "trash -c" or "rc" to clear all garbages in $HOME_TRASH_PATH\033[0m"
   echo -e "\033[33m-2- Use "trash -d" or "rm" to mv the file into $HOME_TRASH_PATH\033[0m"
   echo -e "\033[33m-2- Use "trash -r" to "rr" to mv the file in garbages to current dir\033[0m"
   echo -e "\033[33m-2- Use "trash -h" to "rh" to show help \033[0m"
}

自動補全

function _cmp_rr()
{
   local cur="${COMP_WORDS[COMP_CWORD]}"
   local options=`ls $HOME_TRASH_PATH`
   COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
}
# 自行查閱complete的用法 complete -F FUNC COMMAND
# -F指定了後面的函式執行結果作為COMMAND的補全內容
complete -F _cmp_rr rr

自啟動

# 將檔案放入~目錄下,命名為(.bash_trash),並在~/.bashrc中新增如下程式碼即可
if [ -f ~/.bash_trash ]; then
  . ~/.bash_trash
fi

基本測試

# 命令舉例
# 命令連續執行
# pwd = ~/test
# 建立所需檔案
$ mkdir a b c
$ touch a/a.a a/a.b a/a.c b/b.a b/b.b b/b.c
$ tree
.
├── a
│   ├── a.a
│   ├── a.b
│   └── a.c
├── b
│   ├── b.a
│   ├── b.b
│   └── b.c
└── c

3 directories, 6 files

# 測試絕對路徑
$ rm /home/aaa/test/a/a.a
$ ls a
a.b  a.c

# 測試絕對路徑
$ rm ~/test/a/a.b
$ ls a
a.c

# 測試相對路徑
$ rm ./a/a.c
$ ls a

# 測試多個檔案
$ rm b/b.a b/b.b b/b.c
$ ls b

# 測試萬用字元
$ rm *
$ ls

# 測試檔案列表
$ rl
==== Garbage Lists in /home/aaa/.trash ====
----Usage------
-1- Use trash -p or rp to list all garbages and real pathes in /home/aaa/.trash
-1- Use trash -l or rl to list all garbages in /home/aaa/.trash
-1- Use trash -c or rc to clear all garbages in /home/aaa/.trash
-2- Use trash -d or rm to mv the file into /home/aaa/.trash
-2- Use trash -r to rr to mv the file in garbages to current dir
-2- Use trash -h to rh to show help
.                      a.b.20180531-20:52:24  b.b.20180531-20:53:01
..                     a.c.20180531-20:52:39  b.c.20180531-20:53:01
a.20180531-20:53:16    b.20180531-20:53:16    c.20180531-20:53:16
a.a.20180531-20:52:06  b.a.20180531-20:53:01  .list

# 測試檔案路徑
$ rp
------------bakup name---------------recover path
a.a.20180531-20:52:06            /home/aaa/test/a
a.b.20180531-20:52:24            /home/aaa/test/a
a.c.20180531-20:52:39            /home/aaa/test/./a
b.a.20180531-20:53:01            /home/aaa/test/b
b.b.20180531-20:53:01            /home/aaa/test/b
b.c.20180531-20:53:01            /home/aaa/test/b
a.20180531-20:53:16              /home/aaa/test/a
b.20180531-20:53:16              /home/aaa/test/b
c.20180531-20:53:16              /home/aaa/test/c

# 測試補全,rr後敲擊2次tab
$ rr [tab][tab]
a.20180531-20:53:16    a.c.20180531-20:52:39  b.b.20180531-20:53:01
a.a.20180531-20:52:06  b.20180531-20:53:16    b.c.20180531-20:53:01
a.b.20180531-20:52:24  b.a.20180531-20:53:01  c.20180531-20:53:16

# 測試恢復檔案
$ rr a.a.20180531-20:52:06
$ tree
.
└── a
    └── a.a

1 directory, 1 file

大功告成。

相關連結

原始檔下載

更多更及時的部落格更新請戳—> KingRumn