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

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].//blog.csdn.net/linsongbin1/article/details/90515091, 2019-05-24/2020-05-03