在Linux上很多常見的壓縮檔案都是.gz檔,.gz 是由 gzip 程式所壓縮後的副檔名。gzip 的歷史已經相當悠久了,提供可接受的壓縮率,速度也還蠻快的,可說是最常用的壓縮格式。但最近幾年 .xz 檔開始流行起來,.xz 檔是由 xz 程式所壓縮出來的,比起 .gz 檔小 30%~50%,當然壓縮速度也慢上不少。近年來連kernel都改成用.xz來釋出了,因為縮個3成5成,的確還不少。
若你想要快速的將.gz轉成的.xz,除了乖乖地解壓再重新壓縮外,也可以透過 pipe 的形式,直接將 .gz 解壓的內容透過轉給 xz 程式壓縮,這樣可以省去寫入磁碟的時間,若是SSD的話更可減少不必要的生命週期消耗。
將gz檔轉換成xz
這個腳本將 .gz 的檔案重新壓縮成 .xz 的檔案,與一般全部重新解壓縮,再壓縮的方式不同。我們利用 Linux 的 pipe 機制,一邊解一邊壓,省去寫入磁碟的消耗。裡面有一大部份的指令都是在檢查例外狀況,例如檔案不存在,或前後檔案不一致。因為最後會將.gz的檔案刪除掉,這種謹慎還是有需要的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#!/bin/bash empty_md5=d41d8cd98f00b204e9800998ecf8427e if [ ! -e "$1" ];then echo "The first argument must be a .gz file" exit 1 fi fn="$1" nfn=`echo "$fn" | sed s/\.gz$//` gunzip -c $fn | md5sum | cut -d' ' -f 1 > /tmp/1 gunzip -c $fn | xz -c > ${nfn}.xz xz -d -c ${nfn}.xz | md5sum | cut -d' ' -f 1 > /tmp/2 diff /tmp/1 /tmp/2 if [ $? -eq 0 ];then md5=`cat /tmp/1` if [ "$empty_md5" = "$md5" ];then echo "Recomoress failed" exit 1 fi echo "Re-Compress Success. Remove .gz file" rm "$fn" else echo "Recomoress failed" fi |
行2: 這是預先知道的解壓縮失敗計算md5的結果。用來判斷是否解壓縮失敗。
行3~5: 判斷要重壓縮的檔名是否存在,不存在則中斷。if判斷式中的 -e 是判斷檔案是否存在,前面加一個!,則代表若不存在才執行裡面的描述。
行7: 將要處理的.gz檔名,另存在變數fn
行8: 因為最後的檔名是.xz檔,所以這一行是要取得去除.gz後的檔名。我們利用sed指令來將.gz取代成空白,這樣就可以得到想要的內容了。
行9: 我們首先將.gz檔透過 gunzip -c 的方式,將結果輸出到 stdout,並用pipe方式輸出給 md5sum 程式。md5sum 程式會計算出內容的校驗碼。由於校驗碼分成碼與檔名的部份,我們直接利用cut命令取出碼的部份,並存在檔案 /tmp/1內。
行10: 再一次,我們將.gz檔解壓縮,並輸出到 stdout。但此時改由 xz 來接手,直接對內容進行壓縮,並將壓縮後的內容,導入到.xz的檔名。
行11: 為了驗証壓縮過程有無問題,結果前後是否一致。我們採用與行9類似的做法,將檔案解壓縮並取得其校驗碼,存入 /tmp/2 中。
行12: 現在我們已經有gz解壓後的校驗碼,與xz解壓後的校驗碼,我們將其比對,若內容一致,則代表壓縮過程中正確無誤。
行13~20: 校驗碼正確的處置。若使用者對一個非 gzip 壓縮的檔案做解壓縮的動作。會導致過程中的gunzip發生錯誤而無輸出,但我們在計算md5時,就算沒有內容仍可以取得一個校驗碼。而行10,也會產生一個正確的.xz檔,但其解壓後也是沒內容的。這會造成md5校驗碼檢查無誤,但實際上確是有問題的狀況。
行14: 取得之前解壓縮計算的校驗碼,由於行13已確認 /tmp/1 與 /tmp/2 相等。所以此行取哪個檔案的內容都可以。
行15: 比較校驗碼是否與空內容的校驗碼相同,若相同則代表過程有誤,不應該判定為成功。
行19~20: 排除所有的例外狀況後,已確認重壓縮成功,便將舊的.gz檔刪除。
行23~23: 這是/tmp/1 與 /tmp/2不相同時,印出的錯誤訊息。