将30天前的文件打包压缩备份,然后删除原文件

今天王岩发了一个shell脚本让大家review一下:

mmddnew=`date "+%Y%m%d"`
basedir="/data/tomcatlog/api/reconciliationFiles/"
echo ${mddnew}
cd ${basedir}
echo "压缩"
find ./ -maxdepth 1 -type f -mtime +30 | xargs tar czvf ./${mmddnew}.tar
echo "移动压缩包"
mv ./${mmddnew}.tar ./bak/
echo "删除旧的文件"
find ./ -maxdepth 1 -type f -mtime +30 -exec echo {} \; -exec rm {} \;

这个脚本做的事情就是 将某个目录下更新时间在30天以前的所有文件(不包括文件夹)打包压缩,备份到另一个目录,然后删除这些文件。

这里面有一个比较严重的问题,就是xargs其实是对命令行参数有个数限制的。如果这个文件夹中文件数很多的话(或者文件名很长的话),会出现这样一个问题。就是xargs会截断你的参数,分多次调用tar命令,而tar的-c选项又会导致覆盖问题。

谷歌一下,发现还真有人遇到这样的问题:关于xargs参数被截断, tar文件被覆盖的问题

他的解决方案是先创建一个空的tar包,然后使用追加的方式打包。

于是王严又改成这个样子了:

mmddnew=`date "+%Y%m%d"`
basedir="/data/tomcatlog/api/reconciliationFiles/"
echo ${mddnew}
cd ${basedir}
echo "压缩"
find ./ -maxdepth 1 -type f -mtime +30 | xargs tar uf ./${mmddnew}.tar
gzip ./${mmddnew}.tar
echo "移动压缩包"
mv ./${mmddnew}.tar.gz ./bak/
echo "删除旧的文件"
find ./ -maxdepth 1 -type f -mtime +30 | xargs rm

先用追加形式打包,再压缩。

但是还是有一个问题:就是文件名称如果包含空格之类的东东,那么打包出来的jar包有点问题。

使用print0选项可以解决这个问题。具体参见 xargs超长参数的处理find中的-print0和xargs中-0的奥妙

于是代码又变成这样了:

mmddnew=$(date +%Y%m%d)
basedir="/data/tomcatlog/api/reconciliationFiles/"
cd ${basedir}
echo "压缩"
find . -maxdepth 1 -type f -mtime +30 -print0 | xargs -0 tar uf ${mmddnew}.tar
gzip ${mmddnew}.tar
echo "移动压缩包"
mv ${mmddnew}.tar.gz ./bak
echo "删除旧的文件"
find . -maxdepth 1 -type f -mtime +30 -print0 | xargs -0 rm -f

最后一个小优化,就是上面的脚本find了两次,一次打包,一次删除。是不是可以合并成一次呢?如果文件打包成功即删除。答案是可以的,使用简单的for循环就可以搞定:

for i in `find . -maxdepth 1 -type f -mtime +30`; do tar uf  ${mmddnew}.tar "$i" && rm "$i" ; done

但是有个小小的缺陷:for in 是对字符串按blanks(空格或者换行)切份的,如果文件名中有空格或者换行,则不行。

tar -u在linux下如果不存在会自动创建,但是在mac下不行,所以还是先创建一个空的tar包好。