当前位置:网站首页 > Linux运维 > 正文

编写Shell回收站预防Linux“删库跑路”

作者:jinxijing发布时间:2019-03-12分类:Linux运维浏览:420


导读:编写Shell回收站预防Linux"删库跑路"Linux中,著名的rm-rf命令删除文件无法直接恢复。因误操作造成"删库跑路"的事件数不胜数。生产环境中通常通过权限、备份恢...

编写Shell回收站预防Linux"删库跑路"

Linux中,著名的rm -rf命令删除文件无法直接恢复。因误操作造成"删库跑路"的事件数不胜数。生产环境中通常通过权限、备份恢复等方式避免此类事件。

 

本文介绍一种基于Shell的"回收站"脚本,可实现类Windows回收站的效果,为rm -rf命令提供挽回的余地。

 

Linux系统恐怖的rm -rf命令

 

 

Linux中,rm -rf命令可永久性删除文件,其中:

rm为删除命令

-r表示递归(删除目录,以及这个目录的所有子目录、子文件)

-f表示强制(不需要询问确认,直接删掉)。

 

例如:删掉/data目录的命令为rm -rf /data

 

在目前Linux常用的ext3、ext4、xfs等文件系统中,被rm -rf的文件无法直接恢复。上述命令如果在生产环境使用,在没有可靠备份的前提下,数据近似于彻底丢失。

 

北京时间2017年1月31日23:00左右,Gitlab系统管理员不慎用rm -rf命令对300G生产环境数据执行了删除操作,当他清醒过来按下ctrl + c来停止删除操作时,却只挽留了4.5G的数据,其余所有数据消失殆尽,最终经过抢救,仍然损失了6个小时的数据。

 

 

基于Linux Shell的回收站编写

 

 

下面基于Linux shell脚本,实现类似于Windows的回收站效果:

 

1、原理

将rm命令替换为mv(移动)命令,删除的文件被移动到指定目录下

 

2、结构

循环:rm -rf后可以接多个文件,需要循环语句,依次移动到回收站

重命名:如果先后删除两个同名文件,回收站中会冲突,因此在移动时要重命名文件

 

3、初步实现(先将rm改为mv,不考虑rm -rf)

在合适的目录下新建shell脚本文件写入以下内容(#号后为注释)

#!/bin/bash                   #     shell脚本通用开头格式,表示bash shell编写的脚本

for file in $*                  #     for循环,file是变量名,$@表示所有变量;

#     如删除a、b、c三文件,则$*表示a b c

#     先让变量file等于a,执行一次do到done的动作

#     再让file等于b,执行一次,以此类推。

do                               #     for循环的固定结构,表示for循环开始

mv $file /recyclebin/$file.`date +%y-%m-%d-%h-%m-%S` 

#     $file表示取file变量当前的值

#     这里要用mv命令移动到/recyclebin/目录下;

#     mv命令能直接重命名,此处在原名后加时间后缀;

#     其中``(后引号)表示引号内的命令会生效;

#     因为要使用date命令获得当前的时间作为后缀。

#     +%y-%m-%d-%h-%m-%S规定时间的格式

#     因为date的默认显示不会精确到秒,需要手动指定

done                            #     for循环的固定结构,表示for循环结束

 

4、其它配置

提前创建/recyclebin目录,作为回收站使用(mkdir /recyclebin)

在配置文件中将rm命令替换为该脚本,可修改/etc/bashrc等配置文件

如:脚本文件为/home/test/rm.sh为例:

在/etc/bashrc末尾添加一行alias rm='sh/home/test/rm.sh '

 

脚本的改进

 

目前的脚本能实现基本的功能,但存在以下问题可优化:

 

1、定期清理回收站

可额外编写一个shell脚本,内容为删除回收站中的所有文件,手动定期执行

改进1:可使用crontab计划任务,周期性自动清空回收站

改进2:可用find命令筛选,例如只保留3天内的文件,3天以外的删除

(注:find文件有ctime、atime、mtime三个时间戳,可用stat命令查看)

 

2、要删除的文件和回收站目录不在一个分区

跨分区mv相当于复制粘贴,在文件很大时,速度很慢。

可考虑在每个分区建立回收站,识别文件所在的分区,分类存放。

或添加一个判断语句,大的文件直接删除,不进入回收站,则脚本改动如下:

#!/bin/bash

for file in $*

do

if [ `du -ms $file | cut -f1` -lt 10 ];then

mv $file /recyclebin/$file.`date +%y-%m-%d-%h-%m-%S`

else

/bin/rm $file

fi

done

 

3、命令后增加了-rf选项的处理

mv是没有-rf选项的。要增加判断语句,如果用户执行rm -rf,需要自动忽略-rf。

此时脚本改动如下:

#!/bin/bash

for file in $*

do

if [ ! -d "$file" ]&&[ ! -f "$file"];then

               if[ "$file" != "-rf" ];then

                          echo "[$file] donot exist"

fi

else  

mv $file /recyclebin/$file.`date+%y-%m-%d-%h-%m-%S`

fi

done

 

实际使用中的注意

1、此种方法对于静态文件生效,误删后从回收站移动回来即可,但对于Oracle数据文件等复杂的动态文件,仍需要依靠备份恢复等高级措施保障可靠性。并不能真正杜绝"删库跑路"。

 

2、该脚本仅提供了一种简易的回收站方案,实际防止误删应从多个方面入手,包括但不限于以下:

避免疲劳运维

严格的权限划分(如果危险物品不能给小孩玩,就别放在小孩碰得到的地方)

敏感操作,流程化、自动化(人管代码,代码管机器,还是人直接管机器?)

定期验证和演练备份

避免层层跳转的登录方式,随时确认自己的身份和位置(gitlab的事故原因是管理员远程了多台服务器,把正确的rm -rf命令敲到了错误的服务器上)

使用开源的safe-rm工具代替原有的rm命令