關於 xargs 引數被截斷,tar 檔案被覆蓋的問題
問題:
目錄下共 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