当我们在Linux系统中卸载软件或清理数据时,经常会使用rm -rf命令去删除某个目录,例如删除/tmp/tektea目录:
# rm -rf /tm/tektea
rm命令的-r和-f这两个参数的man含义如下:
-r, -R, --recursive
remove directories and their contents recursively
-f, --force
ignore nonexistent files, never prompt
所以-r和-f分别表示可递归删除目录和强制删除文件,组合起来就是我们在Linux系统中所熟知的、最暴力的强制删除某个目录的命令了,即便目录下文件正在被读写,也依然会干干净净的删除掉该目录,因为有-f参数,听起来合情合理。但你现在已经看了本文的标题,你开始迷惑了吧?
没关系,下面我们通过一些测试来验证下这个暴力的 rm -rf 命令,看看它是不是真的那么生猛,可以破坏一切目录。
用例1:使用cp命令持续往/tmp/tektea目录下拷贝文件,然后rm -rf /tmp/tektea,测试代码如下
# cat test1.sh
#!/bin/bash
i=1
while true
do
cp /tmp/testfile /tmp/tektea/$i
let i++
done
# cat /tmp/testfile
hi
验证结果:执行bash test1.sh后,rm -rf /tmp/tektea删除成功。
用例2:使用dd命令持续往/tmp/tektea目录下写文件,然后rm -rf /tmp/tektea,测试代码如下
# cat test2.sh
#!/bin/bash
while true
do
dd if=/dev/zero of=/tmp/tektea/ddfile bs=1024 count=1000000000
let i++
done
验证结果:执行bash test2.sh后,rm -rf /tmp/tektea删除成功。
用例3:使用echo命令持续往/tmp/tektea目录下的文件写数据,然后rm -rf /tmp/tektea,测试代码如下
# cat test3.sh
#!/bin/bash
while true
do
echo hi >>/tmp/tektea/echofile
done
验证结果:执行bash test3.sh后,rm -rf /tmp/tektea删除失败,且有以下报错:
# rm -rf /tmp/tektea/
rm: cannot remove `/tmp/tektea': Directory not empty
通过上面的验证,首先我们可以得出这条结论:使用rm -rf命令删除目录时,如果该目录下的文件正在被写入,那么会存在删除失败的可能。
那么,以上三个用例都是在往/tmp/tektea目录写入数据,为什么仅仅是第三个场景会失败呢?
各种迹象都把根因指向到了 rm 命令(有兴趣的朋友可以下载Linux中rm命令的源码走读下),rm命令在-r -f强制删除目录时,其逻辑是这样的:
1)从被删除目录的最里层递归删除文件;
2)当最里层目录A的文件被删除完以后,再删除该层文件夹A;
3)在删除文件夹A前,再检查目录A下是否还有文件,如果有则报错Directory not empty(编外:注意这里了)
现在再来回答这个问题——“为什么仅仅是第三个场景会失败呢?”,不过在回答前,我先给大家展示两个数据:
1. 用例1使用cp往/tmp/tektea目录拷贝数据,15秒大约生成了8600个文件,每秒约573文件,相当于每秒573次写入
2. 用例3使用echo往/tmp/tektea/echofile写数据,15秒大约在echofile中写入了59万行,每秒约40000次写入
所以结合rm的实现和几个用例差异可以清楚的知道——在删除某个目录时,若有进程往该目录写入数据,则需要先停止该进程的服务(或kill掉该进程),所以我们的一些Shell代码在卸载或删除目录时就存在失败的可能。