壓縮技能,是 Linux 工程師的必修課,它對提升資料傳輸效率、降低傳輸頻寬、管理備份資料都有著重要的作用。
而在眾多的壓縮工具中,gzip 算是在開源界裡最常用的一款了。下面,我們就來學習 gzip 壓縮和解壓大法!
gzip 的身世之謎
gzip 的身世其實並不是謎,而是眾人皆知的。
在很久以前,UNIX 作業系統上的壓縮工具叫作 compress,這個壓縮工具採用了很著名的 LZW 壓縮演算法。但是由於 Unisys 和 IBM 擁有 LZW 壓縮演算法的專利,所以 UNIX 作業系統不能再隨意使用這個演算法和這個壓縮工具了。為了解決這個問題,Jean-loup Gailly 編寫了 gzip 壓縮工具,完全替代了有專利爭議的 compress 工具,從此 gzip 誕生了。
gzip 工具還被囊括進了 GNU 專案中,成為了其中的一員。
gzip 初體驗
gzip 只能針對普通檔案(regular file)進行壓縮和解壓,對於資料夾、符號連結等是不支援的。如果你想把多個檔案一起壓縮並打包,gzip 自身也是辦不到的,需要有它的好兄弟 tar 命令來幫助完成。
下面來演示一下 gzip 單獨工作的場景:
#我有一個小視訊
[[email protected] ruanjian]$ ls -l hero.avi
-rw-rw-r-- 1 roc roc 10627631 2月 19 10:37 hero.avi
#用gzip開始壓縮, 命令就是這麼簡單
[[email protected] ruanjian]$ gzip hero.avi
#壓縮後, 原檔案消失, 出現一個以.gz字尾的新檔案, 大小變小了(雖然不多)
#如果壓縮的是文字檔案, 效果會很明顯
[[email protected] ruanjian]$ ls -l hero.avi.gz
-rw-rw-r-- 1 roc roc 10605586 2月 19 10:37 hero.avi.gz
#我們再解壓回來, 只需加-d選項即可
[[email protected] ruanjian]$ gzip -d hero.avi.gz
#完璧歸趙啦
[[email protected] ruanjian]$ ls -l hero.avi
-rw-rw-r-- 1 roc roc 10627631 2月 19 10:37 hero.avi
#如果想在壓縮後, 保留原檔案, 那麼可以用-c選項實現
#-c選項就是讓gzip把壓縮的內容輸出到標準輸出, 而非寫入到檔案中
[[email protected] ruanjian]$ gzip -c hero.avi > hero.avi.gz
雖然 gzip 可以單獨工作,但其實平時大家並不總是這麼用,最常用的方式還是結合 tar 命令一起來用。我們繼續往下看。
gzip 的代言人是 tar
雖然 gzip 常用,但 gzip 性格有些低調,通常是隱藏在 tar 打包工具的背後,為使用者默默地提供著壓縮服務。
這是因為在實際生產環境中,我們遇到的情況通常不是只針對一個檔案進行壓縮,而是針對多個檔案和資料夾一起打包並壓縮。而 tar 就是用來打包用的,所以它自然而然就成了各個壓縮工具的代言人了。
有些同學可能會問,“打包/拆包”“壓縮/解壓縮”有什麼區別?我們用一個生活中的例子來解釋,相信大家會豁然開朗:
-
就像搬家時,我們把每一床棉被都抽成真空,這叫作壓縮,然後把好幾床抽真空的棉被用繩子綑綁起來,這就叫打包。
-
東西搬到新家後,把繩子解開,就是拆包,然後把每床棉被舒展開,讓棉被鬆軟起來,這就是解壓縮。
-
如果不抽真空,只是把幾床棉被簡單地用繩子捆起來,那麼就單獨用tar就好了。
-
如果只有一床棉被,打算抽真空,那麼就用gzip就好了。
-
如果有好多床棉被,既要抽真空,又要捆起來,那麼就要將tar和gzip結合起來使用。
來看看如何拆包解壓
在日常的工作中,拆包解壓,絕對要比壓縮打包的次數多得多。比如我們下載了一個開源軟體之後:
#這是我們下載的開源軟體包, 大小是3.4MB
[[email protected] ruanjian]$ ls -hl curl-7.34.0.tar.gz
-rw-rw-r-- 1 roc roc 3.4M 2月 17 22:52 curl-7.34.0.tar.gz
#我們解壓並拆包, 使用了tar -xzvf這樣的命令用法
#下面輸出的以curl-7.34.0/開頭的好多行, 都是拆包和解壓的過程
[[email protected] ruanjian]$ tar -xzvf curl-7.34.0.tar.gz
curl-7.34.0/
curl-7.34.0/depcomp
curl-7.34.0/mkinstalldirs
curl-7.34.0/docs/
curl-7.34.0/docs/VERSIONS
curl-7.34.0/docs/MAIL-ETIQUETTE
curl-7.34.0/docs/BINDINGS
curl-7.34.0/docs/LIBCURL-STRUCTS
curl-7.34.0/docs/BUGS
curl-7.34.0/docs/libcurl/
curl-7.34.0/docs/libcurl/curl_share_init.3
curl-7.34.0/docs/libcurl/libcurl.3
curl-7.34.0/docs/libcurl/curl_share_strerror.3
curl-7.34.0/docs/libcurl/curl_free.pdf
curl-7.34.0/docs/libcurl/curl_easy_send.html
curl-7.34.0/docs/libcurl/curl_easy_reset.3
(此處省略數百行)
#解壓後, 我們來對比一下解壓前後的大小變化。前面說過, 對於文字或程式碼類的檔案, 壓縮的效果會非常明顯。
[[email protected] ruanjian]$ du -sh curl-7.34.0 curl-7.34.0.tar.gz
20M curl-7.34.0
3.4M curl-7.34.0.tar.gz
#進入到解壓後的資料夾中
[[email protected] ruanjian]$ cd curl-7.34.0/
#這就是拆包解壓後的內容啦
[[email protected] curl-7.34.0]$ ls -F
acinclude.m4 CMakeLists.txt configure.ac include/ m4/ maketgz* RELEASE-NOTES
aclocal.m4 compile* COPYING install-sh* MacOSX-Framework* missing* src/
buildconf* config.guess* curl-config.in lib/ Makefile
mkinstalldirs* tests/
CHANGES config.sub* depcomp* libcurl.pc.in Makefile.am packages/ vs/
CMake/ configure* docs/ ltmain.sh Makefile.in README winbuild/
下面我們回過頭來詳細介紹一下上面這段例子中的知識點。
首先,在 Linux 的世界裡,當我們看到檔案字尾是 .tar.gz 或者 .tgz 時,心裡應該默念“這是用 gzip 壓縮的打包檔案”。對於這類檔案,我們是可以通過 gzip 來解壓的。本例中的 curl-7.34.0.tar.gz 就屬於這類。
其次,解壓時我們用到了 tar-xzvf 這樣複雜晦澀的選項組合,下面來逐一解讀一下:
-
-x
選項:表示要進行拆包動作。
-
-z
選項:表示用 gzip 進行壓縮或解壓縮。如果同時使用了 -x 選項,則表示解壓。如果使用了 -c 選項,則表示壓縮。
-
-v
選項:表示在拆包過程中直播整個過程,把已拆包的檔案顯示出來。
-
-f
選項:表示指定要拆包的檔案(注意,這個選項一定要放在各個選項的最後,也就是要和所指定的檔名挨得最近)。
如果你是第一次看到 -xzvf 選項組合,可能會覺得晦澀難記,沒關係,多用幾次就熟了。我現在手指早已形成了肌肉記憶了。(不知道是該笑還是該哭……)
tar.gz 檔案是怎麼造出來的
我們已經練就了“解壓大法”,接下來,就要學習怎麼建立解壓檔案了。如果你掌握了剛才所講的內容,那麼建立壓縮檔案也並非難事。
[[email protected] ruanjian]$ tar -czvf mygzipfile.tar.gz curl-7.34.0
curl-7.34.0/
curl-7.34.0/winbuild/
curl-7.34.0/winbuild/gen_resp_file.bat
curl-7.34.0/winbuild/MakefileBuild.vc
curl-7.34.0/winbuild/Makefile.msvc.names
curl-7.34.0/winbuild/BUILD.WINDOWS.txt
curl-7.34.0/winbuild/Makefile.vc
curl-7.34.0/config.guess
curl-7.34.0/Makefile.in
curl-7.34.0/CHANGES
curl-7.34.0/ltmain.sh
(此處省略數百行)
#看!我們的tar.gz檔案已經新鮮出爐了
[[email protected] ruanjian]$ ls -l mygzipfile.tar.gz
-rw-rw-r-- 1 roc roc 3567446 2月 19 15:45 mygzipfile.tar.gz
細心觀察的話,你會發現打包壓縮所用的命令是 tar-czvf,和拆包解壓的 -xzvf 非常相似,只是 x 替換成了 c 而已。
-
-c
選項:表示要進行打包動作。
-
-z
選項:表示用 gzip 進行壓縮或解壓縮。如果同時使用了 -x 選項,則表示解壓。如果使用了 -c 選項,則表示壓縮。
-
-v
選項:表示在打包過程中直播整個過程,把已打包的檔案顯示出來。
-
-f
選項:表示指定要打包的檔案,完全可以指定多個,資料夾和檔案都可以。
不想解壓,只想看看
有些時候,我們不確定“葫蘆裡裝的什麼藥”,所以不想直接解壓,只想看看裡面包括了哪些檔案。這時,我們用 tar 命令就可以做到:
[[email protected] ruanjian]$ tar -ztvf curl-7.34.0.tar.gz
drwxr-xr-x 1000/1000 0 2013-12-17 15:51 curl-7.34.0/
-rwxr-xr-x 1000/1000 23566 2013-11-11 15:47 curl-7.34.0/depcomp
-rwxr-xr-x 1000/1000 3538 2013-09-09 06:11 curl-7.34.0/mkinstalldirs
drwxr-xr-x 1000/1000 0 2013-12-17 15:51 curl-7.34.0/docs/
-rw-r--r-- 1000/1000 114456 2013-12-17 06:02 curl-7.34.0/lib/http.c
(此處省略數百行)
我們使用了 -ztvf 選項實現了“只想看看”的效果,其中少了 -x 選項,卻多了 -t 選項:
-
少了
-x
選項:因為我們並不想實際拆包,所以一定要去掉 -x 選項。
-
多了
-t
選項:-t 選項的作用是列出打包檔案中的內容,正好符合我們的需求。
有針對性地解壓某個檔案
通過檢視 tar.gz 檔案中的內容,我們知道了 curl 軟體包中有一個 http.c 檔案。現在我想提取出 curl-7.34.0/lib/http.c 這個檔案,看看它的原始碼,但是又不想把這個軟體壓縮包全部解壓,該怎麼做呢?即我們如何從一個打包壓縮的 tar.gz 檔案中提取出某一個單獨的檔案呢?方法總比問題多,揭曉答案:
#原來就在拆包解壓命令的後面直接加上要提取的檔案全路徑就好了, 簡單!
[[email protected] ruanjian]$ tar -xzvf curl-7.34.0.tar.gz
curl-7.34.0/lib/http.c
curl-7.34.0/lib/http.c
#看, 這就是我們單獨提取出來的檔案
[[email protected] ruanjian]$ tree curl-7.34.0
curl-7.34.0
`-- lib
`-- http.c
1 directory, 1 file
壓縮速度與壓縮強度
有些人追求壓縮的速度,希望快點完成壓縮;而有些人卻更追求壓縮的強度,希望把東西壓縮得越小越好。
gzip 命令確實為使用者提供了這樣的選擇權,包含了九個壓縮級別,分別是 1、2、3、4、5、6、7、8、9:
-
“1 級”表示壓縮速度最快,但強度不高。
-
“9 級”表示壓縮強度最高,但速度較慢。
-
預設情況下是 6 級。
我們來實戰一下。
#這是我們的壓縮物件, 一個足有1.7GB大小的紀錄檔檔案, 它是一個實實在在的純文字檔案
[[email protected] ruanjian]$ ls -hl error.log
-rw-r--r-- 1 roc roc 1.7G 2月 20 14:39 error.log
#我們先用“最快速”的壓縮等級(1級), 同時使用time來精準計時
[[email protected] ruanjian]$ time gzip -1 error.log
real 0m22.322s
user 0m20.983s
sys 0m1.250s
#“最快速”壓縮等級, 耗時是22.3秒, 壓縮後的大小為99MB
[[email protected] ruanjian]$ ls -hl error.log.gz
-rw-r--r-- 1 roc roc 99M 2月 20 14:39 error.log.gz
#然後我們再嘗試“最強”壓縮等級(9級), 同樣也使用time來精準計時
[[email protected] ruanjian]$ time gzip -9 error.log
real 1m3.544s
user 1m2.189s
sys 0m1.256s
#“最強”壓縮等級, 耗時變長了許多, 為1分3秒, 但壓縮後的檔案卻是更小了, 為70MB
[[email protected] ruanjian]$ ls -hl error.log.gz
-rw-r--r-- 1 roc roc 70M 2月 20 14:39 error.log.gz
等級數位不好記的話,可以這樣記:1 表示一步到位,往往一步到位的東西追求的是快,而不是精緻程度。
好了,gzip 命令就講到這裡啦,內容較多,足夠大家消化一兩天了。