tar命令基本、進階使用指北

JasonCeng發表於2020-05-03

tar命令基本、進階使用指北

摘要

打包與壓縮是我們在計算機系統日常使用中必備的一個工具,就如我們在使用Windows系統,也需要類似WinRAR的壓縮軟體來將許多資料、檔案打包成一個檔案,並壓縮其佔用空間。我們在Linux下也需要這樣的工具,Linux下有類似gzip、bzip2之類的壓縮工具,不過,這兩個命令對目錄的壓縮指的是將目錄內的所有檔案“分別”進行壓縮。

那Linux下有沒有類似WinRAR一樣強大的打包工具呢?那就是大名鼎鼎的tar了。tar可以將多個目錄或檔案打包成一個大檔案,同時還可以通過gzip/bzip2的支援,將該檔案同時進行壓縮。更有趣的是,由於tar的使用太廣泛了,以致於目前WinRAR也支援tar.gz檔名的解壓縮。本文我將介紹tar命令的語法構成、引數說明、具體使用以及進階操作。

一、語法構成與引數說明

1. tar語法構成

tar的引數非常多,這裡只講幾個常用引數,更多引數可通過man tar查詢。

[root@centos7-master ~]# tar [-j|-z] [cv] [-f 新建的檔名] filename... <==打包與壓縮
[root@centos7-master ~]# tar [-j|-z] [tv] [-f 新建的檔名] <==檢視檔名
[root@centos7-master ~]# tar [-j|-z] [xv] [-f 新建的檔名] [-C 指定目錄] <==解壓縮

2. tar引數說明

-j:通過bzip2的支援進行壓縮/解壓縮,此時檔名最好為*.tar.bz2,這種壓縮方式效果比gzip壓縮效果更好(壓縮後的檔案更小)
-z:通過gzip的支援進行壓縮/解壓縮,此時檔名最好為*.tar.gz

-c:新建打包檔案,可搭配 -v 來檢視過程中被打包的檔名(filename)
-t:檢視打包檔案的內容含有哪些檔名,重點在檢視檔名。
-x:解打包或解壓縮的功能,可以搭配 -C(大寫)在特定目錄解開。

特別留意:-c、-t、-x 不可同時出現在一串命令列中。

-v:在壓縮/解壓縮的過程中,將正在處理的檔名顯示出來

-f filename:-f 後面要接被處理的檔名,建議 -f 單獨寫一個引數

-C 指定目錄:這個引數用在解壓縮時,若要在特定目錄解壓縮,可以使用這個引數

-p:保留備份資料原本許可權與屬性,常用於備份(-c)重要的配置檔案
-P:保留絕對路徑,即允許備份資料中包含有根目錄/
-exclude=FILE: 在壓縮過程中,排除FILE,不要將FILE打包

3. tarfile與tarball的區別

我們知道tar是一個打包&壓縮命令,它支援僅打包而不壓縮,也支援即打包又壓縮。

如果僅打包,就是tar -cv -f file.tar而已,這個檔案我們稱為tarfile

如果即打包又壓縮,就是tar -jcv -f file.tar.bz2而已,這個檔案我們稱為tarball

二、tar的具體使用

tar最常用的三個命令形式如下:

打包:tar -cv -f filename.tar filename
壓縮:tar -jcv -f filename.tar.bz2 filename
      tar -zcv -f filename.tar.gz filename
查詢:tar -jtv -f filename.tar.bz2
解壓縮:tar -jxv -f filename.tar.bz2 -C 指定解壓縮目錄

這裡說明一下,-f filename是緊接在一起的,但很多文章會寫成-jcvf filename,這樣也是對的。但由於引數的順序理論上可調整,有些同學會寫成-jvfc filename,其實也可以執行,但是會導致產生的檔名變為x,因為f後面緊跟的是c,系統會將f後面的內容識別為檔名。

所以建議還是把-f filename與其他引數獨立開來寫,可以避免不必要的問題出現。

但經過在Centos7上的實驗,若引數f不寫在最後(filename前面),會無法執行,說明Centos7對tar命令做了優化處理,具體如下:

[root@centos7-master ~]# tar -jvfc test_tar.tar.bz2 ./test_tar
tar: You must specify one of the `-Acdtrux' or `--test-label'  options
Try `tar --help' or `tar --usage' for more information.

三、tar進階

1. -p 引數:保留檔案的許可權與屬性資訊,且去掉根目錄進行打包&壓縮

使用tar -p保留備份資料的原本許可權與屬性。下面以備份etc目錄為例:

[root@centos7-master ~]# tar -jpcv -f /root/etc.tar.bz2 /etc
tar: Removing leading `/' from member names <==注意這個警告訊息
# -p引數會保留原文字檔案的許可權與屬性

我們查閱一下剛剛備份的etc目錄長什麼樣。

[root@centos7-master ~]# tar -jtv -f /root/etc.tar.bz2
...前面省略...
-rw-r--r-- root/root      2000 2019-08-06 21:44 etc/ntp.conf
drwxr-xr-x root/root         0 2020-05-01 20:25 etc/smartmontools/
-rw-r--r-- root/root      6774 2020-04-01 12:32 etc/smartmontools/smartd.conf
drwxr-xr-x root/root         0 2020-04-01 12:32 etc/smartmontools/smartd_warning.d/
-rwxr-xr-x root/root      5586 2020-04-01 12:32 etc/smartmontools/smartd_warning.sh

我們發現一個有趣的事情,那就是每個檔名都沒了根目錄。這也是上面我們在打包etc目錄時遇到的那個警告訊息tar: Removing leading `/' from member names(刪除了檔名開頭的`/')所告知的情況。

那為什麼要去掉根目錄呢?

主要是為了安全。我們知道,使用tar備份的資料可能會需要解壓縮回來使用,tar -jtvf命令所檢視到的檔名就是解壓縮後的實際檔名。

設想一下,如果沒有去掉根目錄,解壓縮後的檔名就會是絕對路徑,即解壓縮後的資料一定會被放置到/etc/xxx去。如此一來,系統原本的/etc/下面的資料就會被備份資料所覆蓋掉了,這是一件很可怕的事情。

但如果我們在壓縮的時候使用-p引數,即可去掉根目錄,假設我們將備份資料在/tmp中解開,那麼解壓縮後檔案所在的路徑就會是/tmp/etc/xxx。這樣系統本身的/etc/就不會被覆蓋了~

2. -P引數:保留根目錄進行打包&壓縮

如果你確實有需要備份根目錄到tar檔案中,那可以使用-P(大寫)引數。

[root@centos7-master ~]# tar -jpPcv -f /root/etc.and.root.tar.bz2 /etc
...省略中間過程...
[root@centos7-master ~]# tar -jtf /root/etc.and.root.tar.bz2
...省略前面的輸出...
/etc/smartmontools/
/etc/smartmontools/smartd.conf
/etc/smartmontools/smartd_warning.d/
/etc/smartmontools/smartd_warning.sh

可以看到,使用-P引數後,檔名內的根目錄就會存在。

3.僅解壓單一檔案的方法

(1) 找到我們想要的檔名,如shadow檔案

[root@centos7-master ~]# tar -jtv -f /root/etc.tar.bz2 | grep 'shadow'
---------- root/root       422 2020-05-01 20:34 etc/gshadow
---------- root/root       409 2020-05-01 20:25 etc/gshadow-
---------- root/root       786 2020-05-01 20:34 etc/shadow <==這是我們要的
---------- root/root       762 2020-05-01 20:25 etc/shadow-

(2) 將該檔案解開,語法與實際方法如下:

[root@centos7-master ~]# tar -jxv -f 打包的檔案.tar.bz2 待解開檔名
[root@centos7-master ~]# tar -jxv -f /root/etc.tar.bz2 etc/shadow

4. --exclede=FILE: 打包某目錄,但不包含某些檔案的方法

這裡我們打包/etc/ /root 這幾個目錄,但排除/root/etc*開發的檔案,排除我們本次打包新生成的檔案/root/system.tar.bz2(不要打包自己),以此為例。

[root@centos7-master ~]# tar -jcv -f /root/system.tar.bz2 --exclude=/root/etc* \
> --exclude=/root/system.tar.bz2 /etc /root

5. --newer-mtime=time 僅備份比time時刻還要新的檔案

(1) 先由find找出比/etc/passwd還要新的檔案

[root@centos7-master ~]# find /etc -newer /etc/passwd
...過程省略...
# 此時會顯示出比/etc/passwd這個檔案的mtime還要新的檔名

[root@centos7-master ~]# ll /etc/passwd
-rw-r--r-- 1 root root 1107 May  1 20:34 /etc/passwd

(2) 使用tar進行打包,日期為上面看到的2020/05/01

[root@centos7-master ~]# tar -jcv -f /root/etc.newer.then.passwd.tar.bz2 \
> --newer-mtime="2020/05/01" /etc/*
...中間省略...
/etc/X11/
/etc/X11/applnk/ <==這些是成功備份的檔案
/etc/X11/fontpath.d/
...中間省略...
tar: /etc/yum.repos.d/CentOS-Vault.repo: file is unchanged; not dumped
tar: /etc/yum.repos.d/CentOS-fasttrack.repo: file is unchanged; not dumped #這些是沒有被備份的檔案

(3) 顯示出檔案

[root@centos7-master ~]# tar -jtv -f /root/etc.newer.then.passwd.tar.bz2 | \
> grep -v '/$'
#grep -v 表示排除掉符合後面所跟條件的檔案

6. 使用tar將檔案打包到某些特殊裝置中

磁帶機(tape)由於是一次性讀取/寫入裝置,因此我們不能夠使用類似cp等命令來複制。如果想要將/home/etc/root 備份到磁帶機(/dev/st0)時,可以用以下命令:

[root@centos7-master ~]# tar -cv -f /dev/st0 /home /root /etc

7. 特殊應用:利用管道命令與資料流

tar有一種特殊的使用方式,那就是通過標準輸入輸出的資料流重定向(standard input/standard output),以及管道命令(pipe)的方式,將待處理的檔案一邊打包一邊解壓縮到目標目錄去。

# 將/etc整個目錄一邊打包一邊在/tmp中解開
[root@centos7-master ~]# cd /tmp
[root@centos7-master ~]# tar -cvf - /etc | tar -xvf -
# 要注意到,前面的壓縮命令中,輸入檔案變成 - ;後面的解壓縮命令中,輸出命令也變成 - ;且中間有 | 作為管道
# 對於 - 的理解,可以將 - 想象成在記憶體中的一個裝置(緩衝區—)
# 這種方式類似於cp -r /etc /tmp 但無需中間檔案存在,可以將其看作是另一種方式進行復制的行為

參考文獻

[1] 鳥哥(著).王世江(改編).鳥哥的Linux私房菜基礎學習篇[M].北京:人民郵電出版社,2010.254-258
[2] Sam哥哥.Linux grep -v 命令排除輸出[DB/OL].https://blog.csdn.net/linsongbin1/article/details/90515091, 2019-05-24/2020-05-03