关于 xargs 参数被截断,tar 文件被覆盖的问题

原创
2012/09/10 23:00
阅读数 5.4K
问题:
目录下共 2W+ 个小文件:

$ find . -type f | wc -l  
20083  
如果我们这样打包,会爆出 "Argument list too long" 的错误:

$ tar zcf test.tar.gz *  
-bash: /bin/tar: Argument list too long  
这是由于 * 展开后参数长度超过系统参数 ARG_MAX 的限制
为了不报这种错误,我们考虑用find的参数扩展来试试:
$ find . -type f -name "120150_*" | xargs tar zcvf 120150.tar.gz  
这个执行下来没有报错,但是 120150.tar.gz 中并没有包含全部的文件:

$ gzip -d 120150.tar.gz && tar tf 120150.tar | wc -l  
3407  
 
Linux 有个系统参数,用来控制命令行下参数的长度(包含环境数据),这个参数是 ARG_MAX ,在正式环境上是 131072 (bytes) :

$ getconf ARG_MAX  
131072  
    凡是超过 131072 bytes 长度的参数都会被截断, * 分批 * 传给 xargs 后面的参数。所以我猜想,第二批参数列表产生的压缩包把第一批参数列表产生的压缩包覆盖掉了,第三批又把第二批覆盖掉了。。。实际上只有最后一次传进来的参数被打进了压缩包中。

解决办法:

先追加打包所有文件,再压缩:

FILE_NUM=$(find . -type f | wc -l)  
logger "$BID FILE_NUM = $FILE_NUM"  
if [[ $FILE_NUM -gt $FILE_TRANSFER_LIMIT ]];then  
  logger "FILE_NUM More than $FILE_TRANSFER_LIMIT"  
  # 先用tar创建一个空的tar包,"tar cf null.tar" 会报错:"tar: Cowardly refusing to create an empty archive"  
  tar uf ./$BID.tar  
  # 用xargs追加进去所有的文件,这次不用怕被截断了~  
  find . -name "${BID}_*" | xargs tar uf ./$BID.tar  
  # 然后再压缩  
  gzip ./$BID.tar  
else  
  logger "FILE_NUM Less than $FILE_TRANSFER_LIMIT"  
  tar zcf ./$BID.tar.gz "$BID"_*  
fi


其实 xargs 这些用法的区别有些类似于 http 协议中 " 幂等 " 的概念, tar cf 这种命令是不 " 幂等 " 的, rm 这类的命令则是 " 幂等 " 的,有兴趣的同事可以参考这个链接: http://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE#.E5.AE.89.E5.85.A8.E5.8F.8A.E5.B9.82.E7.AD.89.E6.96.B9.E6.B3.95 
展开阅读全文
打赏
0
3 收藏
分享
加载中

引用来自“panzhc”的评论

xargs命令有个参数,可以对参数进行分组。

你指的是 -n 限制参数长度的吧?
2012/09/11 09:20
回复
举报
xargs命令有个参数,可以对参数进行分组。
2012/09/11 07:03
回复
举报
更多评论
打赏
2 评论
3 收藏
0
分享
返回顶部
顶部