今天做了一件非常糟糕的事情, 由于一个玩笑导致朋友用 rm 误删了很多重要的文件。

起初是因为印象里 Mint 中 sudo rm -rf / 这个指令不会被执行, 以为 macOS 中也是这样, 但很快就被现实打脸了。

为了防止类似的悲剧再次发生, 我也开始思考怎样避免这种危险的操作 (除了管好我的嘴之外)。

safe-rm

第一种最简单的方法, 安装 safe-rm, 你可以在它的官方网站中下载安装并查看相关的说明文档。

它的使用十分简单, 下载并解包后, 复制 safe-rm 文件到 /usr/bin 路径, 并配置到 $PATH 靠前的位置。

$ cp safe-rm /usr/bin/safe-rm
export PATH="/usr/bin/safe-rm:$PATH"

(此处 PATH 的配置仅为示例, 请根据你的实际情况修改)

你可以通过 safe-rm 指令使用它, 此外, 虽然我并不推荐, 但你的确可以通过 alias rm='safe-rm' 来延续你输入 rm 的习惯。

但是在使用这些指令前, 务必要将重要的路径加入 safe-rm 黑名单。

  • 对于整个计算机的所有用户, 你可以配置 /etc/safe-rm.conf 文件, 你可能需要 sudo 提升权限才能进行保存
  • 对于当前用户, 你可以配置 ~/.config/safe-rm 文件

在黑名单的配置文件中加入类似下面格式的内容:

/
/etc
/usr
/usr/lib
/var

其中每一行代表一个受保护的路径, 出现在这里的路径, 在使用 safe-rm 删除时将会被跳过:

$ safe-rm -rf /
safe-rm: skipping /

不过, 这仍旧不能阻止使用 /bin/rm 来进行删除的操作。

-i

或者, 你可以为 rm 指令添加 -i 选项, 再删除时向你确认。

如果担心自己忘记, 你可以为 rm 创建别名:

$ vi ~/.bashrc
alias rm='rm -i'
$ source ~/.bashrc

同时, 在重要的路径下创建名为 -i 的文件, 例如:

touch -- /-i /usr/-i /bin/-i /sbin/-i /etc/-i

但是, -i 文件并不能阻止形如 rm -rf ./*rm -rf /etc/* 的指令。

chattr

在重要的路径下创建一个排名靠前的文件 0, 并设置不可删除:

$ touch /0
$ chattr +i /0

但需要注意的是, 这对 -f 选项是无效的, 其它文件依旧会被删除。

回收站机制

此外还可以尝试使用脚本做一些变通, 例如为准备一个回收站功能, 使用 rm 时不直接删除, 而是移入回收站。

举个例子, 首先我们新建一个 .sh 脚本:

$ vi ~/.saferm.sh

将下面的脚本内容写入:

TRASH_DIR="/Users/elias/.rmtrash"

for i in $*; do
    STAMP=`date +%s`
    fileName=`basename $i`
    mv $i $TRASH_DIR/$fileName.$STAMP
done

其中 /Users/elias/.rmtrash 是回收站路径, 依据你的实际情况进行修改即可。

接着, 为 rm 创建别名:

$ vi ~/.bashrc

依据情况加入:

alias rm='/Users/Meniny/.saferm.sh'

保存退出, 重启终端或执行 source ~/.bashrc

你可以进行一些测试:

$ touch 1.txt
$ rm 1.txt
$ ls -a ~/.rmtrash
.	  ..  	1.txt.1481211880

当然, 实际使用中我们经常用到 rm 的各种选项, 删除文件夹也是很平常的事情, 那么要用到的脚本将远非如此简单, 此处仅为示例。

防止空变量

前一段时间网络上流传一个类似的事件, 在执行 rm -rf $FOO/ 时变量为空, 导致直接执行了 rm -rf /

对于这种情况, 一定要做好预防, 务必要对变量进行检查:

[[ -n $F00 ]] && rm -rf $FOO

总而言之

总而言之, 并没有十分完美的方案来阻止 rm 误操作, 很大程度上依旧取决用操作习惯。