使用已刪除的文檔指令碼 既然有了一個被刪除檔案的目錄,而且這個目錄是在使用者的家目錄下的隱藏目錄,那麼一個讓使用者檢索這些已刪除檔案的指令碼的程式就會非常有用了。不管怎樣,想要表明所有可能發生的情況是很難的,因為它包括了沒有匹配、僅有一個匹配以及多個匹配三種情況。在多個匹配的情形中,比如,你是想要挑出最新的檔案,然後將它還原?還是指明有多少種情況匹配成功,然後就退出?又或是展示下不同情況的資料然後供使用者挑選?下面,讓我們來看看我們到底都能做些什麼... 001#!/bin/sh002 003 # unrm.sh -- 尋找已刪除文檔中的給定檔案或是目錄004 # 如果有多個匹配,那麼給出一個按時間戳記排序的結果清單,005 # 然後,讓使用者指定還原哪個006 007 mydir="$HOME/.deleted-files"008 realrm="/bin/rm"009 move="/bin/mv"010 011 dest=$(pwd)012 013 if [ ! -d $mydir ]; then014 echo "`basename $0`: No deleted files directory: nothing to unrm" >&2015 exit 1016 fi017 018 cd $mydir019 020 if [ $# -eq 0 ]; then021 echo "Contents of your deleted files archive(sorted by data):" 022 # ls中的-F是給列出來的項增加指標,比如,檔案不加尾碼,目錄加斜杠/,可執行檔加星號*023 # ls中的-C是按照列顯示024 ls -FC | sed -e 's/\([[:digit:]][[:digit:]]\.\)\{5\}//g' \025 -e 's/^/ /' # 這條替換的目的是給行頭加空格026 exit 0027 fi028 029 # 否則,我們必須使用一個使用者指定的模式。030 # 讓我們來看看該模式在文檔中是否匹配多個檔案或是目錄031 032 matches="$(ls *"$1" 2> /dev/null | wc -l)"033 034 if [ $matches -eq 0 ]; then035 echo "No match for \"$1\" in the deleted file archive." >&2036 exit 1037 fi038 039 if [ $matches -gt 1 ]; then040 echo "More than one file or directory match in the archive:"041 index=1042 # ls中的-t是按照最近修改時間顯示043 # ls中的-d是只顯示目錄的名字,而不是顯示目錄中的內容044 for name in $(ls -td *"$1")045 do046 datetime="$(echo $name | cut -c1-14 | \047 awk -F. '{print $5"/"$4" at "$3":"$2":"$1}')" # 使用awk格式化輸出048 if [ -d $name ]; then049 size="$(ls $name | wc -l | sed 's/[^[:digit:]]//g')" # 算出$name這個目錄中檔案的數目050 echo "$index) $1 (contents = ${size} itmes, deleted = $datetime)"051 else052 size="$(ls -sdk1 $name | awk '{print $1}')" # 計算檔案的大小053 echo "$index) $1 (size = ${size}Kb, deleted = $datetime)"054 fi055 index=$(($index+1))056 done057 echo ""058 echo -n "Which version of $1 do you want to restore ('0' to quit)? [1]: "059 read desired060 if [ ${desired:=1} -ge $index ]; then061 echo "$(basename $0): Restore canceled by user: index value too big." >&2062 exit 1063 fi064 065 if [ $desired -lt 1 ]; then066 echo "$(basename $0): canceled by user." >& 2067 exit 1068 fi069 070 restore="$(ls -td1 *"$1" | sed -n "${desired}p")"071 072 if [ -e "$dest/$1" ]; then073 echo "\"$1\" already exists in this directory. Cannot overwrite." >&2074 exit 1075 fi076 077 echo -n "Restoring file \"$1\"..."078 $move "$restore" "$dest/$1"079 echo "done."080 081 echo -n "Delete the additional copies of this file? [y]: "082 read answer083 084 if [ ${answer:=y} = "y" ]; then085 $realrm -rf *"$1"086 echo "deleted"087 else088 echo "additional copies retained."089 fi090 else091 if [ -e "$dest/$1" ]; then092 echo "\"$1\" already exists in this directory. Cannot Overwrite." >&2093 exit 1094 fi095 096 restore="$(ls -d *"$1")"097 098 echo -n "Restoring file \"$1\"..."099 $move "$restore" "$dest/$1"100 echo "done."101 fi102 103 exit 0指令碼如何工作:第一個大段的代碼,if [ $# -eq 0 ]條件語塊,會按此執行:如果沒有參數給定,那麼就列出刪除文檔中的所有內容。但這裡有個地方隱瞞了。我們並不能展示真實的檔案名稱,因為我們並不想使用者看到時間戳記,這些時間戳記只是用來在內部保護檔案名稱之間並不會相互衝突用的。為了用一種更美觀方式展示檔案名稱,sed運算式刪除了開始的5個數欄位。如果給定了一個參數,它就是要恢複的檔案名稱或是目錄了。下一步就是要查明有多少個能匹配給定的名稱。下面的陳述式完成了這個功能:1matches="$(ls *"$1" 2> /dev/null | wc -l)"在ls的參數中有對不常用的引號,它們是用來保證該模式會匹配到已嵌入空白的檔案名稱,而萬用字元'*'則被shell適當的擴充了。而2> /dev/null保住了命令中產生的錯誤資訊會被拋棄掉,不會讓它們顯示給使用者看到。丟棄的資訊絕大部分有可能是No such file or directory,一般都是由於沒找到給定的檔案名稱引起的。如果對給定的檔案或是目錄名有多個匹配,最複雜的指令碼部分,就是if [ $matches -gt 1 ]語塊。這個語塊,展示了所有的結果。在for迴圈中的ls命令中使用-t選項,會將文檔按照從新到舊排序顯示。然後的awk語句將檔案名稱中的時間戳記給分割了開來。下面的ls中內含的-k選項是用來計算檔案大小時使用KB(kb)作為單位,而不是平時的位元組。1size="$(ls -sdk1 $name | awk '{print $1}')"指令碼會在每個匹配的目錄中顯示檔案的數目,而不是毫無意義的只是顯示匹配檔案項的大小。一個目錄中項的數目事實上很容易計算,使用wc命令:1size="$(ls $name | wc -l | sed 's/[^[:digit:]]//g')"一旦使用者給定一種可能的匹配檔案或是目錄,對應的副檔名就會被下面的語句定義好:1restore="$(ls -td1 *"$1" | sed -n "${desired}p")"這個句子包含了一點sed的另類用法。使用-n選項,然後是一個跟著列印命令p的數字(${desired}),這種方法可以很快的從輸入資料流中提取給定行號的行。 運行指令碼: 有兩種方法呼叫指令碼。第一種,無參數,它會顯示刪除文檔中所有的檔案和目錄。第二種,有一個要求的檔案或是目錄名作為參數,指令碼要麼會恢複該檔案或是目錄(如果只有一個匹配),要麼會顯示可以恢複的所有的候選名單,這樣使用者就可以自行選定一個。 運行結果: 無參數時,指令碼會顯示所有的刪除文檔: 1unrm.sh2Contents of your deleted files archive(sorted by data):3.a.txt .a.o* .adir/有一個檔案名稱做參數:1unrm.sh a.txt2 More than one file or directory match in the archive:3 1) a.txt (size = 4Kb, deleted = 11/18 at 17:15:45)4 2) a.txt (size = 4Kb, deleted = 11/18 at 17:15:10)5 6 Which version of a.txt do you want to restore ('0' to quit)? [1] 27 Restoring file "a.txt"...done.8 Delete the additional copies of this file? [y] y9 deleted分析指令碼: 如果你執行這個指令碼,那麼就有一個潛在的危險需要注意。沒有任何控制或是限制的話,在刪除文檔中的檔案或是目錄會無限制增加。為了避免這點,可以添加一個cronjob來減少文檔。保留14天內的文檔應當時比較合理的了。