10分钟

任务 2 编写Shell脚本实现回收站效果

任务目的

编写Shell脚本rm.sh,实现回收站效果。具体效果为:调用rm.sh删除文件时,先判断文件大小。删除小文件时直接把文件放在相同目录的隐藏回收站中,并自动设置计划任务,超过时间阈值后(7天)自动删除。删除大文件(超过1024M)则提示用户文件过大,询问是否永久删除,如果永久删除则调用rm删除,如果不永久删除,则按照小文件的处理方法,同样放进回收站,延期自动清理。

任务步骤

1.建立测试目录

建立测试目录/test,用作Shell脚本初稿的编写,以及后续测试文件的存放。

mkdir /test
cd /test
建立测试目录

2.创建脚本文件

建立Shell脚本文件rm.sh,编写Shell脚本的基本格式。

vim rm.sh
i
#!/bin/bash
按ESC键
:w
Shell脚本文件的创建

3.编写基本循环体

Linux系统的rm命令有同时删除多个文件的用法,例如rm file1 file2 file3,需要对多个文件一一操作。因此rm.sh脚本整体为循环语句,对后面的各个文件(用预定义变量$*表示)依次处理。此处使用for循环即可。在Shell脚本中添加以下循环体:

for FILE in $*
 do

 done

其中FILE为自定义变量,$*表示执行该文件时后面附带的所有参数(即要删除的各个文件的文件名)。dodone之间为循环体,FILE每取一个$*的值,就进行一次循环,循环到$*的最后一个文件后,自动终止循环。

基本循环体编写

4.进行文件判断

判断文件是否存在,如指定文件不存在则跳过该文件,进入下一个文件的循环。在Shell脚本中添加以下if判断语句:

  if [ ! -w $FILE ];then
   echo "Warning: File [$FILE] not exists.Skip this file."
   continue
  fi

此处-w表示:只有后面的文件确实存在,且当前用户具备写权限,才会判断为“真”(如果没有写权限也就不能删除)。如果满足则返回1,如不满足,则提示文件不存在或不能删,跳过这个文件。

判断文件是否存在

5.确定回收站目录位置

设置回收站隐藏目录的位置,用自定义变量RECYCLEBINDIR表示,此处参照Windows、HDFS等常用回收站的做法,将回收站目录放在被删文件的同一分区路径下,避免跨硬盘分区移动文件的效率问题。在Shell脚本中添加以下if判断语句:

  if [ "`dirname "$FILE"`" = '.' ];then
        RECYCLEBINDIR="`pwd`/.RECYCLEBIN"
   elif [ "`dirname "$FILE"`" = '/' ];then
        RECYCLEBINDIR="/.RECYCLEBIN"
   else
        RECYCLEBINDIR="`dirname "$FILE"`/.RECYCLEBIN"
  fi

此处考虑到用户删除文件时,可能使用绝对路径(如/test/123.txt)或相对路径(如abc.txtdata/abc.txt),格式有差别,需要分情况处理。分别使用basenamedirname命令获取文件名和文件所在的目录,拼接出文件的绝对路径,在路径下放置一个.RECYCLE目录即可,以.(点)开头表示隐藏文件,将回收站目录隐藏起来。

设置回收站目录位置

6.新建回收站目录

新建回收站目录,并设置回收站权限为所有人可用。在Shell脚本中添加以下语句:

  mkdir -p $RECYCLEBINDIR 2>/dev/null

  if [ $? -ne 0 ];then
    echo "Permission denied.Can't delete file [$FILE]. Skip this file."
    continue	
  fi

  chmod 777 $RECYCLEBINDIR

其中mkdir -p命令表示新建目录,如果该目录已存在,则直接使用已存在的目录即可。但如果用户对当前目录没有权限,无法新建(没有写权限,也就不能再进行后面的删除),此时不进行报错(使用2>/dev/null将报错直接丢弃)。使用if语句判断,一旦返回值非0(表示上一条新建目录命令未成功),则提示权限不足,跳过本轮循环,进入下一个文件的处理。

回收站目录的新建与权限设置

7.编写删除文件函数

删除分成“放入回收站”和“彻底删除”两种,分别对应大文件和小文件的删除。使用函数实现,便于后面的重复调用,增加代码的模块化和可读性。在Shell脚本中添加以下语句:

  function MoveFileToRecyclebin()
  {
   mv $FILE ""$RECYCLEBINDIR"/`basename $FILE`.`date +%Y-%m-%d-%H-%M-%S`"
   at now+7day <<< "/usr/bin/rm -rf ""$RECYCLEBINDIR"/`basename $FILE`.`date +%Y-%m-%d-%H-%M-%S`"">/dev/null 2>/dev/null
  }

  function RemoveFileForever()
  {
   /usr/bin/rm -rf $FILE
  }

其中MoveFileToRecyclebin()函数表示移动文件到回收站,其中回收站目录已经在上文中赋值给RECYCLEBINDIR目录。直接使用mv命令把文件移动进去即可。针对连续删除多个同名文件的情况,mv同时进行重命名,在文件后添加date +%Y-%m-%d-%H-%M-%S格式的时间作为文件后缀,避免重名文件的冲突,也便于后续按时间查找被删除的对象。删除文件后,调用at创建计划任务,通过<<<直接将命令重定向给at作为计划任务的内容,7天后使用rm命令自动删除这个文件,释放空间。创建计划任务会在命令行产生反馈信息,用>/dev/null 2>/dev/null直接丢弃反馈信息,不需要显示。

RemoveFileForever()函数则直接调用系统rm命令进行文件删除,释放空间。此处rm命令使用全路径/usr/bin/rm。主要用于删除大文件,给用户警告和提示,是否不经回收站直接删掉(Windows中也有类似的大文件提示机制)。

函数实现删除文件

8.对文件进行删除处理

在Shell脚本中添加以下语句:

  SIZE=`du -ms $FILE | awk '{print $1}'`
  if [ "$SIZE" -gt "1024" ];then
   echo "Warning: File $FILE is too large("$SIZE"M),delete it forever? y/n"
   while read answer
     do
      if [ "$answer" == "y" ];then
        RemoveFileForever
        break
      elif [ "$answer" == "n" ];then
        MoveFileToRecyclebin
        break
      else
        echo "Please input y or n"
      fi
     done
  else
  MoveFileToRecyclebin
  fi

主要逻辑为:使用du -ms判断文件大小。-ms获取文件或目录的总大小,以MB为单位,去掉后面的其他信息,把单纯的数值赋值给自定义变量SIZE

SIZE的大小进行判断,超过1024MB则询问是否不经过回收站彻底删除,使用read函数获取用户的键盘输入内容,赋值给自定义变量answer进行判断。删除文件属于敏感操作,因此设置循环,如果用户输入不是yn,就一直询问用户,直到用户输入yn为时才执行删除操作(输入y则调用RemoveFileForever函数彻底删除,输入n则调用MoveFileToRecyclebin移动至回收站),并break跳出循环。

如果文件不大于1024M,不需要询问,直接调用MoveFileToRecyclebin函数移动至回收站。

删除文件的逻辑编写

9.保存文件

以上内容编写完毕后,保存文件并退出。

按ESC回到普通模式
:
wq