第8章 Linux文件類型及查找命令實踐

第8章 Linux文件類型及查找命令實踐

8.1 Linux文件屬性概述

在Linux系統中,文件或目錄的屬性主要包括:索引節點(Inode)、文件類型、權限屬性、鏈接數、所歸屬的用戶和用戶組、最近修改時間等內容。

執行ls-lhi命令可以顯示/data目錄下內容的常見屬性信息,示例如下:


[[email protected] ~]# ls -lhi /data
total 12K
139170 -rw-r--r--. 1 root root 22 Mar 11 15:17 oldboy.txt
139167 -rw-r--r--. 1 root root 22 Mar 11 15:16 oldgirl.txt
139171 -rw-r--r--. 1 root root 38 Mar 11 15:37 test.txt

有關文件屬性的詳細解釋如圖8-1所示。

圖8-1中各列的具體含義說明如下。

第一列:Inode索引節點編號(相當於人的身份證、家庭住址,全國唯一);系統讀取文件時首先通過文件名找到Inode號碼,然後才能讀取到文件內容。

第二列和第三列:文件類型及權限。這一列共包含11個字符,其中第一個字符爲文件類型,隨後的9個字符爲文件的對應權限,最後一個字符點號「.」是與SELinux有關的一個標識。

第四列:硬鏈接個數(詳情請參看ln命令的講解)。相當於超市的多個入口,可以從不同的文件入口進入文件,還可以互爲備份(消防通道)。

圖8-1 文件屬性每一列的含義

第五列:文件或目錄所屬的用戶(屬主)。在Linux系統裏,文件和程序的存在必須要有用戶和組滿足相應的存在需求。

第六列:文件或目錄所屬的組(屬組)(家庭)。

第七列:文件或目錄的大小。

第八列:文件或目錄的修改時間,默認爲月、日、時、分。

第九列:實際的文件名或目錄名。需要注意的是,文件名不算文件的屬性。

接下來的幾章,將爲大家重點講解這些文件屬性的含義,以及與之相關的重要的Linux基礎知識,本章先介紹Linux文件類型。

8.2 Linux文件類型及文件擴展名

8.2.1 文件類型與擴展名介紹

我們都知道,Windows系統是通過擴展名來區分不同文件類型的,如果擴展名錯誤,或者沒有擴展名,則會導致文件無法直接打開(如圖8-2所示)。

圖8-2 Windows下面修改擴展名後系統的提示

表8-1爲Windows系統下常見文件的擴展名及代表的意義。

表8-1 Windows下常見文件的擴展名及意義

Linux系統不同於Windows系統,Linux系統不會根據擴展名來區分文件類型,而是通過爲文件設定屬性的特殊方式來區分文件類型的。但是Linux系統中也會包含各種帶有擴展名的文件,這些文件可能來自於Windows及其他系統,也有部分來自Linux系統本身,但這些文件的擴展名,並不代表文件的類型,這些擴展名只是爲了讓用戶更容易區分文件類型,更易讀而已,並且即使出現擴展名錯誤,文件也是可以正常使用的。

表8-2給出了Linux系統下常見文件的擴展名及其代表的意義。

表8-2 Linux下常見文件的擴展名及意義

在Linux系統中,對於通過應用程序或命令創建的文件,如file.txt、file.tar.gz等,雖然這些文件的擴展名不同,而且要使用不同的程序或命令來打開,但它們都是常規文件(也稱爲普通文件)。

Linux中文件結尾附帶的後綴文件擴展名(如.txt、.tar、.gz),除了讓曾經習慣Windows的用戶感覺更易讀之外,對於Linux系統來說,大多數沒有特別實際的意義,通常也只是爲了易讀而已,但在Windows系統中,擴展名就是用來實實在在地表示文件類型格式的。

8.2.2 Linux中的文件類型

在Linux系統中,可以說一切(包括目錄、普通文件、設備文件等)皆爲文件。文件類型包含了普通文件、目錄、字符設備文件、塊設備文件、符號/軟鏈接文件、管道文件等,表8-3列出了Linux下常見的文件類型及說明。

表8-3 Linux下常見的文件類型及說明

要想查看文件類型,可執行ls-l或ls-al命令來實現,執行後的輸出信息如下:


[[email protected] ~]# ls -l
total 52
-rw-------. 1 root root  1074 Mar  8 09:57 anaconda-ks.cfg
drwxr-xr-x. 2 root root  4096 Mar 10 18:01 data1
-rw-r--r--. 1 root root 21736 Mar  8 09:57 install.log
-rw-r--r--. 1 root root  5890 Mar  8 09:55 install.log.syslog
-rw-r--r--. 1 root root    18 Mar 12 04:00 oldboy.txt
-rw-r--r--. 1 root root    20 Mar 11 15:28 oldgirl.txt

上述結果中的第一列(比如-rw-r--r--)對應的第一個字符就是描述文件類型的,比如上面結果中就有「-」、d等類型的文件。第2~10個字符(比如rw-r--r--)是用來描述文件權限的(有關權限問題後文會有詳細介紹)。

提示:Linux初學者在學習時需要抓住重點,建議大家先掌握d、「-」、l這三種類型。

以下是find命令中與-type參數對應的可選文件類型信息。


b      block (buffered) special
c      character (unbuffered) special
d      directory
p      named pipe (FIFO)
f      regular file
l      symbolic link; 
s      socket
D      door (Solaris)

8.2.3 Linux文件類型詳細介紹

1.普通文件(regular file)

執行echo命令生成一個普通文件oldboy.txt,然後執行ls-l oldboy.txt查看其屬性:


[[email protected] ~]# echo "I am oldboy" >oldboy.txt
[[email protected] ~]# ls -l oldboy.txt 
-rw-r--r--. 1 root root 12 Mar 13 02:46 oldboy.txt

通過ls-l命令來查看oldboy.txt文件的屬性時,可以看到第一列的內容爲-rw-r--r--,這裏的第一個符號是「-」(英文字符減號),在Linux中,以這樣的字符開頭的文件就表示普通文件。

這些文件一般是用相關的應用程序或系統命令創建而成的,比如touch、cp、echo、cat、>、>>等工具命令。若是將Windows裏各種擴展名的文件拿到Linux系統下查看,你會發現它們的文件類型都是普通文件,示例代碼如下:


[[email protected] oldboy]# ls -l oldboy.jpg arp.zip test.doc oldboytrainning.ppt 
-rw-r--r-- 1 root root 145756 Oct 31 11:03 arp.zip
-rw-r--r-- 1 root root  36120 Aug 10 15:56 oldboy.jpg
-rw-r--r-- 1 root root  12800 Oct 31 11:04 oldboytrainning.ppt
-rw-r--r-- 1 root root  10752 Oct 31 11:04 test.doc

從上面的測試可以看出,Windows下doc、ppt、zip、jpg等格式的文檔在Linux下都屬於普通文件。Linux下各種服務的配置文件(如/etc/services、/etc/hosts等)也都是純文本文件。

普通文件(regular file)的第一個特徵就是其屬性開頭爲「-」,按照文件內容,又大略可以分爲如下三種。

1)(純)文本文件(ASCII):此類文件的文件內容可以直接讀取到數據,例如,字母、數字、特殊符號等。可以用cat命令讀文件,比如Linux系統裏的配置文件幾乎都是這種類型。

2)二進制文件(binary):Linux中的常見命令就屬於這種格式。例如,cat命令就是一個二進制文件。

3)數據格式文件(data):有些程序在運行的過程中會讀取某些特定格式的文件,那些特定格式的文件即稱爲數據文件。例如,Linux在用戶登錄時都會將登錄的數據記錄在/var/log/wtmp(last命令的數據庫文件)文件內,該文件是一個數據文件,可通過last命令讀取出來。但如果使用cat命令讀取則會讀出亂碼。因爲它屬於一種特殊格式的文件。

若要刪除普通文件,則可以使用rm命令來實現。

2.目錄文件(directory)

可執行make命令生成/data目錄,然後執行ls-ld命令查看目錄的屬性,示例代碼如下:


[[email protected] ~]# mkdir /data -p
[[email protected] ~]# ls -ld /data /etc
drwxr-xr-x.  2 root root 4096 Mar 11 15:37 /data
drwxr-xr-x. 78 root root 4096 Mar 11 03:45 /etc

從上面的輸出可以看到,第一列的內容爲drwxr-xr-x.,這種開頭帶有d字符的文件就表示目錄,可以認爲目錄在Linux中是一種特殊的文件。

可以通過mkdir命令或cp命令(帶-r或-a參數)來創建目錄,cp命令可以將一個目錄複製爲另一個目錄。刪除目錄可使用rm-r或rmdir(刪空目錄纔可以)命令。

下面是ls-F命令的執行結果,它會在不同文件的結尾加上特殊標識,用以區分文件。可以看出,目錄的結尾是/,其他文件的結尾,有的也加上了特殊符號。


[[email protected] oldboy]# ls -F
arp.zip  ext/  oldboy.jpg   oldboytrainning.ppt  test.doc  xiaodong/
[email protected]  oldboy*  oldboy_hard_link*  test/  wodi.gz

3.符號鏈接(symbolic link)文件

符號鏈接文件也稱爲軟鏈接文件,它類似於Windows下的快捷方式,它本身並沒有內容,而是指向了其他實體文件。示例代碼如下:


[[email protected] ~]# cat oldboy.txt 
I am oldboy
[[email protected] ~]# ln -s oldboy.txt oldboy_soft.txt #ln -s  爲誰創建軟鏈接(源文件)  軟鏈接名(名字不能事先存在)
[[email protected] ~]# ls -l oldboy*
lrwxrwxrwx. 1 root root 10 Mar 13 03:14 oldboy_soft.txt -> oldboy.txt
-rw-r--r--. 1 root root 12 Mar 13 02:46 oldboy.txt
[[email protected] ~]# cat oldboy_soft.txt 
I am oldboy

從上面的輸出可以看到,當我們查看文件的屬性時,會看到有類似lrwxrwxrwx的內容,注意第一個字符是l,這類文件類型即表示軟鏈接文件。

軟鏈接文件可以通過ln命令進行創建,具體命令爲「ln-s源文件名新文件名」,如果不使用-s參數,則表示創建硬鏈接文件,硬鏈接文件不適用於目錄。

有關鏈接文件的知識,後文會進一步詳細講解。

4.字符(character)/塊(block)設備文件

若想查看/dev目錄下特定文件的屬性,則會看到類似如下的內容:


[[email protected] ~]# ls -l /dev/tty /dev/sda1
brw-rw----. 1 root disk 8, 1 Mar 10 12:26 /dev/sda1
crw-rw-rw-. 1 root tty  5, 0 Mar 10 12:26 /dev/tty

其中,/dev/tty文件的第一列屬性是crw-rw-rw-,前面的第一個字符是c,其表示字符設備文件。對於字符設備,一般典型的文件就是串行端口的接口設備,如貓等串口設備。

而/dev/sda文件的第一列屬性是brw-r-----,前面第一個字符是b,其表示塊設備,塊設備就是存儲數據供系統及程序訪問的接口設備,如硬盤、光驅等都均屬於塊設備。

塊設備和字符設備文件都是比較特殊的文件,一般都是實體設備接入到計算機後的設備,但是也可以使用mknod命令來模擬創建,並用rm命令來刪除。在實際工作中,創建上述設備文件一般不需要通過命令實現。下面創建特殊文件的知識瞭解一下即可。

創建一個字符設備(字符設備文件與此相同)的示例代碼如下:


[[email protected] ~]# mknod oldboy c 5 1
[[email protected] ~]# ls -l oldboy
crw-r--r--. 1 root root 5, 1 Mar 13 03:26 oldboy

以下是相應的說明。

·oldboy是創建的設備的名字。

·c表示創建的是字符設備,也可以使用b。

·5是該設備在major.h中定義的標記。

·1是第一個子設備。

5.套接口(socket)文件

當啓動數據庫軟件MySQL服務時,會產生一個mysql.sock文件。在這個文件的屬性裏,第一個字符是s,表示是套接字文件。示例代碼如下:


[[email protected] oldboy]# ll /data/3306/mysql.sock 
srwxrwxrwx 1 mysql mysql 0 03-18 09:36 /data/3306/mysql.sock
[[email protected] ~]# ls -l /dev/log
srw-rw-rw- 1 root root 0 Feb 12  2012 /dev/log

.sock文件也是一類特殊的文件,這類文件通常在網絡之間進行數據連接,例如,我們可以啓動一個程序來監聽客戶端的請求,客戶端可以通過套接字來進行數據通信。示例代碼如下:


mysql -uroot -ppass -S /data/3306/mysql.sock

以上便是MySQL數據庫客戶端程序連接服務器端的命令,並通過套接字文件與數據庫服務器進行通信的示例。有關數據庫連接的命令,等講解到數據庫時再詳細介紹,這裏簡單瞭解一下就行了。大家也可以使用man socket命令瞭解相關信息。

6.管道(pipe)文件

管道文件(FIFO)也是一個特殊的文件類型,主要用於解決多個程序同時訪問一個文件所造成的錯誤,第一個字符爲p。FIFO是First-In First-Out的縮寫,此文件類型瞭解即可或者乾脆略過,因爲運維工作中極少涉及它。示例代碼如下:


[[email protected] ~]# ll /var/spool/postfix/public/qmgr
prw--w--w-. 1 postfix postfix 0 Mar 13 03:31 /var/spool/postfix/public/qmgr
提示:可以執行man fifo詳細瞭解。

8.3 文件及目錄查找命令

8.3.1 file:顯示文件的類型

1.命令詳解

【命令星級】  ★★★★☆

【功能說明】

file命令用於顯示文件的類型。

【語法格式】


file  [option]  [file]
file  [選項]    [<文件或目錄>] 

【選項說明】

表8-4針對file命令的參數選項進行了說明。

表8-4 file命令的參數選項及說明

2.使用範例

範例8-1:通過file命令查看文件類型。


[[email protected] ~]# file oldboy oldboy.txt oldboy_soft.txt 
oldboy:          character special
oldboy.txt:      ASCII text                   #<==oldboy.txt是ASCII文本。
oldboy_soft.txt: symbolic link to `oldboy.txt'#<==oldboy_soft.txt指向oldboy.txt符號鏈接。
[[email protected] ~]# file /etc
/etc: directory                               #<==etc是個目錄。

8.3.2 which:顯示命令的全路徑

1.命令詳解

【命令星級】  ★★★★★

【功能說明】

which命令用於顯示命令的全路徑,我們常用這個命令查找命令在哪裏,which命令查找的範圍是PATH環境變量的路徑。

【語法格式】


which  [option]  [programname]
which  [選項]     [命令名] 

說明:

which命令用於在PATH環境變量裏查找指定的命令。

【選項說明】

表8-5針對which命令的參數選項進行了說明。

表8-5 which命令的參數選項及說明

2.使用範例

範例8-2:通過which命令查找指定命令全路徑。


[[email protected] ~]# echo $PATH      #<==先查看環境變量。
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
[[email protected] ~]# which date      #<==查看date命令的全路徑。
/bin/date
[[email protected] ~]# which which       #<==如果指定命令設置了別名,則使用which功能將會顯示別名情況。
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
    /usr/bin/which
[[email protected] ~]# which cd          #<== Bash內置命令無法使用which。
/usr/bin/which: no cd in (/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin)

範例8-3:參數-a的測試。


[[email protected] ~]# which mysql   #<==該實驗需要MySQL服務環境。
/usr/local/sbin/mysql 
[[email protected] ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
[[email protected] ~]# PATH=$PATH:/application/mysql/bin/ #<==添加路徑到環境變量。
[[email protected] ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/application/mysql/bin/
[[email protected] ~]# which -a mysql  #<==所有包含mysql命令的路徑都顯示出來了。
/usr/local/sbin/mysql
/application/mysql/bin/mysql     #<==/application/mysql路徑是老男孩編譯的mysql路徑。

8.3.3 whereis:顯示命令及其相關文件全路徑

1.命令詳解

【命令星級】  ★★★★☆

【功能說明】

whereis命令用於定位指定命令的可執行文件、源碼文件及man幫助文件的路徑。

【語法格式】


whereis  [option]  [filename]
whereis  [選項]     [文件名] 

說明:

whereis命令用於在PATH環境變量裏查找指定的命令。

【選項說明】

表8-6針對whereis命令的參數選項進行了說明。

表8-6 whereis命令的參數選項及說明

2.使用範例

範例8-4:通過whereis命令將相關的文件都查找出來。


[[email protected] ~]# whereis svn
svn: /usr/bin/svn /usr/share/man/man1/svn.1.gz
[[email protected] ~]# whereis -b svn  #<==只查找可執行文件。
svn: /usr/bin/svn
[[email protected] ~]# whereis -m svn  #<==只查找man幫助文件。
svn: /usr/share/man/man1/svn.1.gz
[[email protected] ~]# whereis -s svn  #<==只查找源代碼文件。
svn:                             #<==沒有找到相應的文件。

提示:Linux工程師在工作中用得最多的還是查找命令所在的路徑,因此which更常用。

8.3.4 locate:快速定位文件路徑

1.命令詳解

【命令星級】  ★★★★☆

【功能說明】

在Linux系統裏有一個名爲mlocate.db的數據庫文件,這個文件包含系統文件的文件名及對應的路徑信息。故而,locate命令查找文件時不用遍歷磁盤,而是直接查找mlocate.db文件,這樣可以快速給出結果。但這也會存在一個問題,如果是新添加的文件,那麼mlocate.db文件就會沒有記錄,對此,在使用locate命令時可以先用updatedb命令更新一下mlocate.db數據庫文件。當然,mlocate.db還會由系統自帶的定時任務執行updatedb命令定期更新。

特別提示:該命令軟件包在CentOS7中默認未安裝,如果需要使用此命令,則要提前安裝和配置,具體命令如下:


[[email protected] ~]# yum install mlocate -y   #<==安裝命令對應的軟件包。
[[email protected] ~]# updatedb                 #<==初始化命令查找的數據庫。

【語法格式】


locate  [option]  [pattern]
locate  [選項]     [文件名] 

說明:

locate命令用於從數據庫查找指定的命令。

【選項說明】

表8-7針對locate命令的參數選項進行了說明。

表8-7 locate命令的參數選項及說明

2.使用範例

範例8-5:通過locate命令查看數據庫。


[[email protected] ~]# ll -h /var/lib/mlocate/mlocate.db     #<==locate查找的數據庫文件。
-rw-r----- 1 root slocate 1.4M Nov 16 18:32 /var/lib/mlocate/mlocate.db
[[email protected] ~]# cat /etc/cron.daily/mlocate.cron     #<==系統自帶的定時任務腳本。
[email protected] ~]# cat /etc/cron.daily/mlocate          #<==系統自帶的定時任務腳本,C6的名稱爲mlocate.cron。
#!/bin/sh
nodevs=$(awk '$1 == "nodev" && $2 != "rootfs" && $2 != "zfs" { print $2 }' < /proc/filesystems)
renice +19 -p $$ >/dev/null 2>&1
ionice -c2 -n7 -p $$ >/dev/null 2>&1
/usr/bin/updatedb -f "$nodevs"

範例8-6:查找文件路徑。


[[email protected] ~]# locate pwd         #<==直接跟想要查找的文件名,只要是包含pwd字符串的都能找出來。
/bin/pwd
/etc/.pwd.lock
/etc/latrace.d/pwd.conf
/lib/modules/2.6.32-573.el6.x86_64/kernel/drivers/watchdog/hpwdt.ko
/sbin/unix_chkpwd
/usr/bin/pwdx
/usr/include/pwd.h
/usr/lib/x86_64-redhat-linux5E/include/pwd.h
/usr/lib64/cracklib_dict.pwd
/usr/lib64/python2.6/lib-dynload/spwdmodule.so
……
[[email protected] ~]# locate -c pwd       #<==只顯示匹配的行數。
28

範例8-7:使用通配符查找文件路徑。


[[email protected] ~]# locate /etc/sh    #<==只要部分符合就輸出。
/etc/shadow
/etc/shadow-
/etc/shells
[[email protected] ~]# locate /etc/sh*   #<==還可以使用通配符。
/etc/shadow
/etc/shadow-
/etc/shells
[[email protected] ~]# locate -c /etc/*sh*
25

8.3.5 updatedb:更新mlocate數據庫

1.命令詳解

【命令星級】  ★★★☆☆

【功能說明】

updatedb命令可以創建或更新locate命令使用的數據庫。updatedb命令會被定時任務定期(每天)執行,此命令與locate在一個軟件包裏,在CentOS7下需要單獨安裝,見locate命令的安裝方法。

【語法格式】


updatedb  [option]  
updatedb  [選項]

【選項說明】

表8-8針對updatedb命令的參數選項進行了說明。

表8-8 updatedb命令的參數選項及說明

2.使用範例

範例8-8:查看數據庫。


[[email protected] ~]# ll -h /var/lib/mlocate/mlocate.db  #<==這就是要被更改的數據庫文件。
-rw-r----- 1 root slocate 1.4M Nov 16 18:32 /var/lib/mlocate/mlocate.db

範例8-9:更新數據庫。


[[email protected] ~]# locate oldboy          #<==查看包含oldboy的文件。
/root/oldboy.log
[[email protected] ~]# touch oldboy20191116 
[[email protected] ~]# locate oldboy          #<==再次查看,發現新建的oldboy20191116文件沒有顯示。
/root/oldboy.log
[[email protected] ~]# updatedb -vU /root/     #<==-v顯示更新過程,-U指定更新路徑。
/root/.viminfo
/root/oldboy20191116
/root/anaconda-ks.cfg
/root/install.log
……
[[email protected] ~]# locate oldboy          #<==再次查看,發現oldboy20191116文件出現了。
/root/oldboy.log
/root/oldboy20191116
[[email protected] ~]# ll -h /var/lib/mlocate/mlocate.db
-rw-r----- 1 root slocate 707 Nov 16 20:41 /var/lib/mlocate/mlocate.db #<==時間變了。

8.3.6 find:查找目錄下的文件

1.命令詳解

【命令星級】  ★★★★★

【功能說明】

find命令用於查找目錄下的文件,同時還可以調用其他命令執行相應的操作。

【語法格式】


find  [-H] [-L] [-P] [-D debugopts] [-Olevel]   [pathname]   [expression] 
find  [選項]                                    [路徑]       [操作語句]

說明:

注意子模塊的先後順序。

圖8-3爲find命令語法的使用說明。

圖8-3 find命令語法的使用說明

【選項說明】

表8-9針對find命令的參數選項進行了說明。

表8-9 find命令的參數選項及說明

2.使用範例

(1)基礎範例

範例8-10:查找指定時間內修改過的文件。


[[email protected] data]# find . -atime -2     #<==「.」代表當前目錄,查找兩天內被訪問的文件使用選項atime,-2代表兩天內。

./file1.txt
./file2.txt
./dir2
./dir3
[[email protected] data]# find /data/ -mtime -5 #<==使用絕對路徑/data/,查找修改時間在5天以內的文件使用選項mtime。
/data/
/data/file1.txt
/data/file2.txt
/data/dir2
/data/dir3


find查找時間的說明圖如圖8-4所示。

圖8-4 find查找時間的說明示意圖

具體說明如下。

·-4:表示文件更改時間距現在4天以內。

·+4:表示文件更改時間距現在4天以前。

·4:表示距現在第4天。

範例8-11:用-name指定關鍵字查找。


[[email protected] data]# find /var/log/ -mtime +5 -name '*.log' #<==在/var/log/目錄下
                                              查找5天前以「.log」
                                                結尾的文件。
/var/log/openv*n.log 

範例8-12:利用「!」反向查找。


[[email protected] data]# find .  -type d #<==-type表示按類型查找,d代表目錄,查找當前目錄下的所有目錄。
.
./dir2
./dir3 
[[email protected] data]# find . ! -type d #<==!表示取反,查找不是目錄的文件,注意感嘆號的位置。
./file1.txt
./file2.txt 

範例8-13:按照目錄或文件的權限來查找文件。


[[email protected] data]# find /data/ -perm 755 #<==按照文件權限來查找文件,755是權限的數字表示方式。
/data/
/data/dir2
/data/dir3 

範例8-14:按大小查找文件。


[[email protected] data]# find . -size +1000c  #<==查找當前目錄下文件大小大於1000字節的文件。
.
./dir2
./dir3

範例8-15:查找文件時希望忽略某個目錄。


[[email protected] data]# find /data -path "/data/dir3" -prune -o -print
     #<==參數-path用於指定路徑樣式,配合-prune參數用於排除指定目錄。
/data
/data/file1.txt
/data/file2.txt
/data/dir2

代碼中的-path「/data/dir3」-prune-o-print是-path「/data/dir3」-a-prune-o-print的簡寫。其中,-a和-o類似於Shell中的「&&」和「||」,當-path「/data/dir3」爲真時,執行-prune;爲假時,執行-print。

範例8-16:忽略多個目錄。


[[email protected] data]# find /data \(-path /data/dir2 -o -path /data/dir3 \) -prune -o -print 
/data
/data/file1.txt
/data/file2.txt

使用圓括號可以將多個表達式結合在一起,但是圓括號在命令行中另有特殊含義,所以此處使用「\」進行轉義,即告訴bash不對後面的字符「()」作解析,而是留給find命令處理。而且在「\(-path」中左括號和path之間有空格,「dir3\)」中dir3和右括號之間有空格,這是語法要求。

範例8-17:使用user和nouser選項。


[[email protected] data]# chown nobody:nobody file2.txt     #<==chown命令用於改變文件的用戶和用戶組,具體用法見chown命令的講解。
[[email protected] data]# ll -h file2.txt 
-rw-r--r-- 1 nobody nobody 0 Nov  4 14:28 file2.txt
[[email protected] data]# find . -user nobody           #<==查找用戶爲nobody的文件。
./file2.txt
[[email protected] data]# chown 555 file2.txt                 
[[email protected] data]# ll -h file2.txt
-rw-r--r-- 1 555 nobody 0 Nov  4 14:28 file2.txt  #<==如果是這種數字的屬主就需要使用-nouser參數了。
[[email protected] data]# find . -nouser                #<==查找沒有對應任何用戶的文件。   
./file2.txt 

這個例子是爲了查找那些屬主賬戶已經被刪除的文件,使用-nouser選項時,不必給出用戶名。

範例8-18:使用group和nogroup選項。


[[email protected] data]# find . -group nobody   #<==這個功能與上一個例子類似,此處是查找用戶組爲nobody的文件。
./file2.txt 
[[email protected] data]# chown .555 file2.txt     
[[email protected] data]# ll -h file2.txt          
-rw-r--r-- 1 555 555 0 Nov  4 14:28 file2.txt
[[email protected] data]# find . -nogroup          #<==查找沒有對應任何用戶組的文件。
./file2.txt

範例8-19:查找比某個文件新或舊的文件。

如果希望查找更改時間比某個文件(file1)新,但比另一個文件(file2)舊的所有文件,可以使用-newer選項。它的一般形式爲:-newer file1!-newer file2。其中,「!」是邏輯非符號,即取反的意思。


[[email protected] data]# ll -h          
total 8.0K
drwxr-xr-x 2 root root 4.0K Nov  4 14:26 dir2
drwxr-xr-x 2 root root 4.0K Nov  4 14:26 dir3
-rw-r--r-- 1 root root    0 Nov  4 14:28 file1.txt
-rw-r--r-- 1  555  555    0 Nov  4 16:27 file2.txt
-rw-r--r-- 1 root root    0 Nov  4 16:26 file3.txt
[[email protected] data]# find . -newer file1.txt #<==在當前目錄查找更改時間比文件file1.txt新的文件。
.
./file3.txt
./file2.txt
[[email protected] data]# find . -newer file1.txt ! -newer file2.txt 
#<==查找更改時間比文件file1.txt新但比file2.txt舊的文件。
.
./file3.txt
./file2.txt #<==包含file2.txt。

範例8-20:邏輯操作符的使用。


[[email protected] oldboy]# find . -maxdepth 1 -type d #<==-maxdepth 1查找一級目錄,類似於tree -L 1。
.
./test
./xingfujie
./a
./ext
./xiaodong
./xiaofan
[[email protected] oldboy]# find . -maxdepth 1 -type d ! -name "."  #<==使用感嘆號「!」取反,不輸出名字爲點的行。
./test
./xingfujie
./a
./ext
./xiaodong
./xiaofan
[[email protected] oldboy]# find . -maxdepth 1 -type d ! -name "." -o -name "oldboy"  
#<==-o表示或的意思,顯示除「.」以外的所有目錄或文件名爲oldboy的文件。
./test
./oldboy
./xingfujie
./a
./ext
./xiaodong
./xiaofan
[[email protected] oldboy]# find . -maxdepth 1 -type d ! -name "." -a -name "ext" 
#<==-a在這裏是並且的意思,查找不爲點號並且名字爲ext的目錄,最後結果只顯示名爲ext的目錄。       
./ext

範例8-21:find正則表達式的用法。

由於-name參數只支持「*」、「?」、「[]」這三個通配符,因此在碰到複雜的匹配需求時,就會用到正則表達式。

find正則表達式的語法如下:


find pathname -regextype "type" -regex "pattern"

示例代碼如下:


[[email protected] ~]# find / -regex "find"  #<==給出的正則表達式必須要匹配完整的文件路徑。
[[email protected] ~]# find / -regex ".*find"
/bin/find
/usr/bin/oldfind
/usr/bin/find
/usr/share/doc/subversion-1.6.11/tools/client-side/wcfind
/usr/src/kernels/2.6.32-504.el6.x86_64/include/config/generic/find
[[email protected] ~]# find / -regex ".*/find"
/bin/find
/usr/bin/find
/usr/src/kernels/2.6.32-504.el6.x86_64/include/config/generic/find

正則表達式的類型默認爲emacs,還有posix-awk、posix-basic、posix-egrep和posix-extended等。下面是posix-extended的示例代碼:


[[email protected] data]# find . -regextype "posix-egrep" -name '*[0-9]' 
./dir2
./dir3

需要說明的是,上面正則表達式的使用只是給大家拓展一下知識,在實際工作中用得比較少。

範例8-22:ls-l命令放在find命令的-exec選項中執行。


[[email protected] data]# find . -type f -exec ls -l {} \;
-rw-r--r-- 1 root root 0 Nov  4 16:26 ./file3.txt
-rw-r--r-- 1 root root 0 Nov  4 14:28 ./file1.txt
-rw-r--r-- 1 555 555 0 Nov  4 16:27 ./file2.txt 
#<==find命令匹配到了當前目錄下的所有普通文件,並在-exec選項中使用ls -l命令將它們列出。

詳細說明如下。

-exec後面跟的是command命令,最後以分號(;)作爲結束標誌,考慮到各個系統中分號會有不同的意義,所以前面要加反斜槓對分號進行轉義。

這裏需要注意如下幾點。

·{}的作用:指代前面find命令查找到的文件或目錄。

·{}前後都要有空格。

·command可以是其他任何命令,例如,示例代碼中的ls、rm等命令。

範例8-23:在目錄中查找更改時間在n天以前的文件,並刪除它們。


[[email protected] data]# find . -type f -mtime +14 -exec rm {} \;
    #<==find命令在目錄中查找更改時間在14天以前的文件,並在-exec選項中使用rm命令將它們刪除。

範例8-24:使用-exec選項的安全模式-ok。


[[email protected] data]# find /var/log/ -name "*.log" -mtime +5 -ok rm {} \;
< rm ... /var/log/anaconda.ifcfg.log > ? n
< rm ... /var/log/anaconda.log > ? n
< rm ... /var/log/anaconda.yum.log > ? ^C
#<==find命令在/var/log/目錄中查找所有文件名以.log結尾、更改時間在5天以前的文件,並刪除它們,到此爲止,-ok的功能與-exec一樣,但是-ok還有一個功能,即在刪除之前先給出提示,指出按y鍵表示刪除文件,按n鍵表示不刪除文件,這樣操作會比較安全。

範例8-25:對查找到的文件內容顯示屬性信息。


[[email protected] data]# find . -type f|xargs ls -l  #<==將find命令查找到的普通文件通過管道符號和xargs命令傳給ls命令執行。注意命令格式,這裏使用了管道符號「|」,xargs是一個命令,是向其他命令傳遞參數的一個過濾器,大家可以先去閱讀xargs命令的相關章節之後再來閱讀此部分內容。
-rw-r--r-- 1 root root 0 Nov  4 14:28 ./file1.txt
-rw-r--r-- 1  555  555 0 Nov  4 16:27 ./file2.txt
-rw-r--r-- 1 root root 0 Nov  4 16:26 ./file3.txt

範例8-26:使用xargs執行mv命令的示例。


[[email protected] data]# ls
dir2  dir3  file1.txt  file2.txt  file3.txt
[[email protected] data]# find . -name "*.txt"|xargs -i mv {} dir2/
     #<==使用xargs的-i參數,使得{}代表find查找到的文件,將這些文件以參數的形式放在mv命令後面,作爲要移動的源文件,移動到dir2目錄下。
[[email protected] data]# ls
dir2  dir3
[[email protected] data]# ls dir2/
file1.txt  file2.txt  file3.txt

範例8-27:find結合xargs的-p選項使用的示例。


[[email protected] data]# find dir2 -name "file*"|xargs -p rm -f
rm -f dir2/file3.txt dir2/file1.txt dir2/file2.txt ?...y
[[email protected] data]# ls dir2/
[[email protected] data]#
#<==說明:使用xargs命令的-p選項會提示讓你確認是否執行後面的命令,y表示執行,n表示不執行。

(2)技巧性範例

範例8-28:進入/root目錄下的data目錄,刪除oldboy.txt文件。

這裏提供了多種刪除方法。


①cd /root/data  #<==進入目錄再刪,不使用全路徑,這樣會更安全。
  rm oldboy.txt
②find /root/data -type f -name "*oldboy.txt" |xargs rm –f
③find /root/data -type f -name "*oldboy.txt" -exec rm {} \;

提示:在生產環境中刪除文件推薦使用第②種方法,該方法能夠儘可能地防止誤刪文件。

範例8-29:在/oldboy目錄及其子目錄下的所有以擴展名「.sh」結尾的文件中,將包含「./hostlists.txt」的字符串全部替換爲「../idctest_iplist」。

說明:

此題用到了sed命令的替換功能,讀者如果不是很懂,那麼可以先看下sed命令之後再做這道題。


sed -i 's#./hostlists.txt#../idctest_iplist#g' 文件名  #<==使用sed替換文件內容,然後結合find命令找到需要替換的文件。

方法一:find+exec方法。


find /oldboy -name "*.sh" -exec sed -i 's#./hostlists.txt#../idctest_iplist#g' {} \;

方法二:find+xargs方法。


find /oldboy -name "*.sh"|xargs sed -i 's#./hostlists.txt#../idctest_iplist#g' 

方法三:高效處理方法,find語句兩端是反引號。


sed -i 's#./hostlists.txt#../idctest_iplist#g' `find /oldboy -name "*.sh"`  #<==前面說過,如果一個命令語句中還有反引號,優先執行反引號中的命令。

範例8-30:將/etc下所有的普通文件打包成壓縮文件。

此題涉及了tar命令的用法,讀者可以先學會tar命令再來查看這道題。

方法一:使用反引號的方法。


[[email protected] /]# tar zcvf oldboy.tar.gz `find /oldboy -type f -name "test.txt"`  #<==使用反引號的方法最簡單,也最容易理解。
tar: Removing leading `/' from member names
/oldboy/xiaofan/test.txt
/oldboy/ext/test.txt
/oldboy/test/test.txt

方法二:使用xargs的方法。


[[email protected] /]# find /oldboy -type f -name "test.txt"|xargs tar zcvf oldboy01.tar.gz
tar: Removing leading `/' from member names
/oldboy/xiaofan/test.txt
/oldboy/ext/test.txt
/oldboy/test/test.txt

範例8-31:刪除一個目錄下的所有文件,但保留一個指定文件。

假設這個目錄是/xx/,裏面有file1、file2…file10等10個文件,保留一個指定的文件file10,其餘的刪除,示例代碼如下:


[[email protected]  ~]# cd /xx
[[email protected] xx]# touch file{1..10}
[[email protected] xx]# ls
file1  file10  file2  file3  file4  file5  file6  file7  file8  file9

方法一:使用find+xargs命令處理(推薦方法)。


[[email protected] xx]# ls
file1  file10  file2  file3  file4  file5  file6  file7  file8  file9
[[email protected] xx]# find /xx -type f ! -name "file10"|xargs rm -f  #<==核心是使用感嘆號排除file10文件。
[[email protected] xx]# ls
file10

方法二:使用find+exec命令處理(文件多時效率低)。


[[email protected] xx]# find /xx -type f ! -name "file10" -exec rm -f {} \;     
[[email protected] xx]# ls
file10

方法三:使用rsync命令處理(rsync命令後面會講解)。


[[email protected] xx]# ls
file1  file10  file2  file3  file4  file5  file6  file7  file8  file9
[[email protected] xx]# mkdir /null #<==建立一個空目錄用於rsync刪除文件使用。
[[email protected] xx]# rsync -az --delete --exclude "file10" /null/ /xx/
[[email protected] xx]# ls
file10

這部分內容請參考老男孩的博客:http://oldboy.blog.51cto.com/2561410/1650380。

(3)生產案例

範例8-32:這是幾年前筆者爲一家IT公司做技術顧問時遇到的一個實際問題,當時的一個lamp的服務器裏,站點目錄下的所有文件均被植入瞭如下內容:


<script language=javascript src=http://%4%66E%78%6F%72%67%2E%70%6F/x.js?google_ad=93x28_ad></script>

包括圖片文件也被植入了上述內容,網站打開時就會調用這個地址,顯示一個廣告,造成的影響很惡劣。雖然現在看起來這個問題很簡單,但當時該公司的Linux運維花了很久都沒搞定,後來經老男孩的指點,很快就搞定了。那麼,具體該如何解決呢?

解決思路是遍歷所有的目錄和所有的文件,把以上被植入的內容刪除掉。

具體的處理過程如下。

1)與運維人員確認問題,並詳細確認問題的情況。

2)制定處理方案,先備份數據,然後,執行命令批量修改回來。

3)寫下解決說明(類似本例這樣),寫完發給運維人員。

4)詢問處理結果,並告知應詳細查看日誌,找出問題發生的根源。

5)提供亡羊補牢的解決方案(站點目錄嚴格權限規劃方案及新上線規範思路)。

從發現問題到解決問題的過程具體如下。

1)運營人員、網站用戶發現問題,網站有彈窗廣告。

2)運營人員報給開發人員,開發人員聯繫運維人員。開發和運維共同解決。

3)開發發現造成這個問題的原因就是所有站點目錄下的文件均嵌入了一段js代碼。

4)運維人員的解決辦法是,先備份出問題的所有原始文件,然後用find+sed替換,如果有備份數據也可以將備份數據還原。

5)詳細查看日誌,尋找問題發生的根源。

6)提供亡羊補牢的解決方案(站點目錄嚴格權限規劃方案及新上線規範思路)。

示例處理命令如下:


[[email protected] ett]# find . -type f|xargs sed -i 's#<script language=javascript src=http://%4%66E%78%6F%72%67%2E%70%6F/x.js?google_ad=93x28_ad></script>##g'

也可以直接清理指定的行,命令如下:


[[email protected] ett]# find . -type f|xargs sed -i '/*x.js?google_ad*/d'

範例8-33:已知Apache服務的訪問日誌按天記錄在服務器本地目錄/app/logs下,由於磁盤空間緊張,現在要求只能保留最近7天的訪問日誌!請問如何解決?

對於這個問題,可以從Apache服務配置上着手,也可以從生成出來的日誌上着手。

首先,生成測試文件,腳本如下(命令行直接執行即可):


for n in `seq 14`
do
    date -s "2014/08/$n"
    touch access_www_`(date +%F)`.log
done
date -s "2014/08/15"

生成的文件如下所示:


[[email protected] log]# ls
access_www_2014-08-01.log  access_www_2014-08-05.log  access_www_2014-08-09.log
access_www_2014-08-13.log
access_www_2014-08-02.log  access_www_2014-08-06.log  access_www_2014-08-10.log
access_www_2014-08-14.log
access_www_2014-08-03.log  access_www_2014-08-07.log  access_www_2014-08-11.log
access_www_2014-08-04.log  access_www_2014-08-08.log  access_www_2014-08-12.log
[[email protected] log]# date -s "2014/08/15"
Fri Aug 15 00:00:00 CST 2014

解決上述問題的方法有如下四種:


①find . -type f -name "access*.log" -mtime +7|xargs rm -f  
②find . -type f -name "access*.log" -mtime +7 -exec rm -f {} \;
③find . -type f -name "access*.log" -mtime +7 -delete  #<==-delete是find命令的參數,可以將查找出的文件刪除。
④從Apache服務配置上着手,用cronolog軟件輪詢日誌
CustomLog "|/usr/local/sbin/cronolog  /app/logs /access_www_%w.log"  combined 
總共生成7天日誌1-7,下週又覆蓋1-7的日誌

(4)拓展知識:將找到的文件移動到指定位置的方法

將找到的文件移動到指定位置,可以採用如下幾種經典方法(同樣適用於cp複製場景)。


方法1:
find . -name "*.txt"|xargs -i mv {} dir2/ #<==xargs的-i參數使得{}可代替find找到的內容。
方法2:
find . -name "*.txt"|xargs mv -t dir2/    #<==mv命令的-t選項前面已講解過,可以顛倒源和目標。
方法3:
mv `find . -name "*.txt"` dir2/         #<==反引號"的作用是優先執行它包含的內容。

方法1中xargs的-i參數使得{}可代替find找到的內容,最終作爲mv命令的源複製到dir2目錄下,而方法2是利用mv的-t命令來顛倒源和目標的,因爲find找到的結果通過xargs默認會作爲命令的目標,即「mv dir2/目標」,這顯然是錯的。方法3是利用mv命令的基本語法,然後將find命令用反引號括起來作爲源進行操作。

(5)拓展知識:find命令結合exec和xargs使用的區別

find命令結合exec和xargs使用的區別具體見表8-10。

表8-10 find命令結合exec和xargs使用的區別

使用-exec選項命令操作的示例及結果如下:


[[email protected] ~]# find . -type f -exec echo oldboyedu {} \;  #<==從命令的執行結果中可以看到,每次獲得一個文件就輸出一次。
oldboyedu ./.viminfo
oldboyedu ./anaconda-ks.cfg
oldboyedu ./install.log
oldboyedu ./install.log.syslog
oldboyedu ./.bash_logout
oldboyedu ./.cshrc
oldboyedu ./ls.txt
oldboyedu ./.bash_history
oldboyedu ./.lesshst
oldboyedu ./oldboy.log
oldboyedu ./test.txt
oldboyedu ./.tcshrc
oldboyedu ./GB2312.txt
oldboyedu ./.bash_profile
oldboyedu ./.bashrc

使用xargs命令操作的示例及結果如下:


[[email protected] ~]# find . -type f |xargs echo  oldboyedu #<==輸出結果只有一行,xargs獲取到所有文件名一次性輸出。
oldboyedu ./.viminfo ./anaconda-ks.cfg ./install.log ./install.log.syslog ./.bash_logout ./.cshrc ./ls.txt ./.bash_history ./.lesshst ./oldboy.log ./test.txt ./.tcshrc ./GB2312.txt ./.bash_profile ./.bashrc

xargs還能控制每行輸出的參數個數,示例代碼如下(更多使用方法見xargs命令):


[[email protected] ~]# find . -type f |xargs -n 3 echo  oldboyedu  #<==使用-n 3指定每次輸出3個參數。
oldboyedu ./.viminfo ./anaconda-ks.cfg ./install.log
oldboyedu ./install.log.syslog ./.bash_logout ./.cshrc
oldboyedu ./ls.txt ./.bash_history ./.lesshst
oldboyedu ./oldboy.log ./test.txt ./.tcshrc
oldboyedu ./GB2312.txt ./.bash_profile ./.bashrc

驗證區別二的案例:


[[email protected] ~]# touch "oldboy edu"     #<==創建一個文件名帶有空格的特殊文件。
[[email protected] ~]# ll -h "oldboy edu"
-rw-r--r-- 1 root root 0 May 17 16:30 oldboy edu
[[email protected] ~]# find . -name "*oldboy*" -exec ls -lh {} \; #<==使用-exec參數正常使用。
-rw-r--r-- 1 root root 0 May 17 16:30 ./oldboy edu
[[email protected] ~]# find . -name "*edu*"|xargs ls -lh          #<==使用xargs命令無法正常打印。
ls: cannot access ./oldboy: No such file or directory
ls: cannot access edu: No such file or directory

8.3.7 xargs:將標準輸入轉換成命令行參數

1.命令詳解

【命令星級】  ★★★★☆

【功能說明】

xargs命令是向其他命令傳遞命令行參數的一個過濾器,它能夠將管道或者標準輸入傳遞的數據轉換成xargs命令後所跟命令的命令行參數。

【語法格式】


xargs  [option]
xargs  [選項]

說明:

xargs命令以及後面的選項之間至少要有一個空格。

【選項說明】

表8-11針對xargs命令的參數選項進行了說明。

表8-11 xargs命令的參數選項及說明

2.使用範例

範例8-34:多行輸入變單行的示例。


[[email protected] ~]# cat test.txt     #<==這是測試文本。
1 2 3 4 5 6
7 8 9
10 11
[[email protected] ~]# xargs < test.txt #<==將所有數字變成一行,注意xargs不能直接接文件,需要結合輸入重定向符「<」。
1 2 3 4 5 6 7 8 9 10 11

範例8-35:通過-n指定每行輸出個數的示例。


[[email protected] ~]# xargs -n 3 < test.txt #<==每行最多輸出3個。
1 2 3
4 5 6
7 8 9
10 11

範例8-36:自定義分隔符(使用-d功能)的示例。


[[email protected] ~]# echo splitXsplitXsplitXsplitX                 #<==echo將文本打印到屏幕上。
splitXsplitXsplitXsplitX
[[email protected] ~]# echo splitXsplitXsplitXsplitX|xargs -d X      #<==以X作爲分隔符。
split split split split
[[email protected] ~]# echo splitXsplitXsplitXsplitX|xargs -d X -n 2 #<==以X作爲分隔符且每行最多輸出2個。
split split
split split

提示:該參數類似於cut命令的-d參數以及seq參數的-s參數。

範例8-37:參數-I可以指定一個替換的字符串。

這個參數的功能不是很好理解,需要做個鋪墊,使用xargs的-i選項可以讓{}代替前面find命令找到的文件或目錄,命令如下:


[[email protected] data]# find . -name "*.log"|xargs -i mv {} dir1/ #<==這個例子在find命令中已經講解過了。
[[email protected]ldboy data]# ls
dir1  file1.txt  file4.txt  file5.txt

從上面的示例代碼中可以看出,使用-i選項可以用{}代替find查找的結果,而-I選項可以指定其他字符代替{},例如[]。


[[email protected] data]# find . -name "file*"|xargs -I [] cp [] dir2
[[email protected] data]# ls
dir1  dir2  file1.txt  file4.txt  file5.txt
[[email protected] data]# ls dir2/
file1.txt  file4.txt  file5.txt
[[email protected] data]#

範例8-38:結合find使用xargs的特殊案例。

我們常用的刪除文件的安全方法是find.-type f-name"*.txt"|xargs rm-f,但有時這個方法還是會出現一些小問題。比如說在tmp目錄下有一個名爲「hello world.txt」的文件,這種情況應該如何刪除它呢?

首先模擬創建看看,直接通過「touch hello world.txt」來創建是不行了,這樣做會創建兩個文件。下面是兩種創建方法。


[[email protected] tmp]# ls
[[email protected] tmp]# touch "hello word.txt"    #<==第一種創建方法。
[[email protected] tmp]# ls
hello word.txt
[[email protected] tmp]# touch hello\ everyone.txt #<==第二種創建方法,反斜線後有一個空格,此時反斜線對空格進行了轉義。
[[email protected] tmp]# ls
hello everyone.txt  hello word.txt

這裏先用find.-type f-name"*.txt"|xargs rm查看一下結果:


[[email protected] tmp]# find . -type f -name "*.txt"|xargs rm
rm: cannot remove `./hello': No such file or directory
rm: cannot remove `word.txt': No such file or directory
rm: cannot remove `./hello': No such file or directory
rm: cannot remove `everyone.txt': No such file or directory

出現上述問題的原因是xargs誤認爲它們的分隔符是空格,解決方法是以字符null分隔輸出,這時使用-0選項,就可以正確執行了,命令如下:


[[email protected] tmp]# find . -type f -name "*.txt" -print0|xargs -0 rm -f
#<==這樣就不會有問題了。
[[email protected] tmp]# ls

8.4 tar:打包壓縮命令

8.4.1 命令詳解

【命令星級】  ★★★★★

【功能說明】

tar是Linux系統裏將多個文件打包在一起並且可以實現將打包的文件解壓的命令。tar是系統管理員最常用的命令之一,tar命令不但可以實現對多個文件進行打包,還可以實現對多個文件打包後進行壓縮。

打包是指將一大堆文件或目錄變成一個總的文件,壓縮則是將一個大的文件通過一些壓縮算法變成一個小的文件。

【語法格式】


tar  [option]  [file]
tar  [選項]     [文件或目錄]

說明:

在tar命令及後面的選項裏,每個元素之間都至少要有一個空格。

【選項說明】

tar命令的參數選項的使用有點特殊,對於CentOS Linux來說「tar-z」和「tar z」效果相同,加或不加「-」這個符號都是可以的,這是重點。具體說明參見表8-12。

表8-12 tar命令的參數選項及說明

8.4.2 使用範例

1.基礎範例

範例8-39:備份站點目錄html。


[[email protected] ~]# mkdir -p /var/www/html/oldboy/test   #<==先生成測試文件。
[[email protected] ~]# touch /var/www/html/{1..5}.html      #<==創建5個待備份文件。
[[email protected] ~]# ls /var/www/html/
1.html  2.html  3.html  4.html  5.html  oldboy 
[[email protected] ~]# cd /var/www/                          #<==進入到目標目錄的上一級目錄打包。
[[email protected] www]# ls
html
[[email protected] www]# tar zcvf www.tar.gz ./html/ 
          #<==選項v會顯示打包的過程,大家需要記住常用的打包命令組合zcvf,如果不想顯示打包過程,則可以省略v選項,即選項組合爲zcf。
./html/
./html/1.html
./html/5.html
./html/3.html
./html/oldboy/
./html/oldboy/test/
./html/2.html
./html/4.html
[[email protected] www]# ll -h www.tar.gz 
-rw-r--r-- 1 root root 260 Nov 18 17:26 www.tar.gz

範例8-40:查看壓縮包內的內容。


[[email protected] www]# tar ztvf www.tar.gz     #<==使用選項t不解壓就可以查看壓縮包的內容,選項v可以顯示文件的屬性。
drwxr-xr-x root/root         0 2019-11-18 17:15 ./html/
-rw-r--r-- root/root         0 2019-11-18 17:26 ./html/10.html
-rw-r--r-- root/root         0 2019-11-18 17:26 ./html/8.html
……
[[email protected] www]# tar ztf www.tar.gz     #<==省略v選項。
./html/
./html/2.html
./html/1.html
……
[[email protected] www]# tar tf www.tar.gz     #<==如果不指定z選項,那麼tar命令也會自動判斷壓縮包的類型,自動調用gzip命令。
./html/
./html/2.html
./html/1.html
……

範例8-41:解壓縮包的示例。


[[email protected] /]# tar zxvf www.tar.gz -C /tmp/     #<==選項C指定解壓路徑,不加C解壓到當前目錄。
./html/
./html/1.html
./html/2.html
……
[[email protected] www]# ls /tmp/html/
1.html  2.html  3.html  4.html  5.html  oldboy 
[[email protected] /]# tar xf www.tar.gz -C /tmp/     #<==如果不想看到太多的輸出,則可以去掉v選項,功能不會受到影響。同時z選項也可以省略,只要涉及解壓的操作,tar命令就能自動識別壓縮包的壓縮類型,但是壓縮時必須要加上z選項。

說明:

tar xfC www.tar.gz/tmp/這種格式也可以,但是沒有上面的命令直觀好記。

範例8-42:排除打包的示例。


[[email protected] www]# tar zcvf www.tar.gz ./html/ --exclude=html/oldboy/test    #<==test目錄的結尾不要加「/」,否則會不成功。
./html/
./html/1.html
./html/5.html
./html/3.html
./html/oldboy/
./html/2.html
./html/4.html
[[email protected] www]# tar zcvf www.tar.gz ./html/ --exclude=html/oldboy/test --exclude=html/oldboy #<==排除2個以上目錄的方法:並列使用多個--exclude。
./html/
./html/1.html
./html/5.html
./html/3.html
./html/2.html
./html/4.html

範例8-43:打包軟鏈接文件的示例。


[[email protected] www]# cd /etc/
[[email protected] etc]# tar zcf local.tar.gz ./rc.local  #<==使用常規參數zcf打包。
[[email protected] etc]# tar tfv local.tar.gz             #<==不解壓查看文件內容。
lrwxrwxrwx root/root         0 2019-02-09 21:59 ./rc.local -> rc.d/rc.local
#<==這裏是一個坑,如果不加特殊參數,那麼打包之後的文件將是個軟鏈接文件,而不是rc.local的實體內容。

採用-h參數打包鏈接文件,示例代碼如下:


[[email protected] etc]# tar zcfh local_h.tar.gz ./rc.local  #<==額外加上h參數進行打包。
[[email protected] etc]# tar tfv local_h.tar.gz               
-rwxr-xr-x root/root       220 2014-10-16 22:53 ./rc.local

對比壓縮包內的文件類型之後,大家應該可以看出區別了吧?利用tar的通用選項zcf打包文件時,如果這個文件是鏈接文件(如/etc/rc.local),那麼tar只會對鏈接文件本身打包,而不是對鏈接文件指向的真實文件打包,因此還需要額外使用-h選項將軟鏈接文件對應的實體文件打包。

2.生產案例

範例8-44:對/etc目錄下所有的普通文件打包。


[[email protected] www]# cd /etc/
[[email protected] etc]# ls
abrt                       inputrc                       quotatab
acpi                       iproute2                      rc
…………
#<==如果etc下包含有目錄、普通文件等,那麼怎樣才能將普通文件找出來並打包在一個文件中?
[[email protected] /]# tar zcvf etc.tar.gz `find etc/ -type f`  
     #<==使用find命令找到所有普通文件,在tar命令語句中嵌套一個反引號包含的find命令語句。
etc/ld.so.conf.d/kernel-2.6.32-573.el6.x86_64.conf
etc/ld.so.conf.d/mysql-x86_64.conf
etc/prelink.conf.d/nss-softokn-prelink.conf
etc/mailcap
…………輸出省略
[[email protected] /]# ll -h etc.tar.gz 
-rw-r--r-- 1 root root 9.3M Nov 18 18:34 etc.tar.gz

8.4.3 經驗技巧

在打包時,有以下經驗技巧可供讀者參考。

1)在打包一個目錄之前,先進入到這個目錄的上一級目錄,然後執行打包命令,這是大部分情況下打包文件的規範操作流程。少數情況下,當打包需要完整的目錄結構時,可以使用絕對路徑進行打包,但是需要注意解壓tar包時壓縮包內的文件是否會覆蓋原始文件。

2)打包模型爲:tar zcf/路徑/筐.tar.gz相對路徑/蘋果。打包其實就是將蘋果放進筐裏。

8.5 date:顯示與設置系統時間

8.5.1 命令詳解

【命令星級】  ★★★★★

【功能說明】

date命令用於顯示當前的系統時間或設置系統時間。

【語法格式】


date  [option]  [+FORMAT]
date  [選項]    [+日期格式]

【選項說明】

表8-13針對date命令的參數選項進行了說明。

表8-13 date命令的參數選項及說明

8.5.2 使用範例

範例8-45:常用時間格式測試例子。

大家可以對着上面的表格逐一測試參數,這裏限於篇幅僅列舉一部分:


[[email protected] ~]# date +%y #<==顯示年(短格式)。
17
[[email protected] ~]# date +%Y #<==顯示年(長格式)。
2017
[[email protected] ~]# date +%m #<==顯示月。
07
[[email protected] ~]# date +%d #<==顯示日。
06
[[email protected] ~]# date +%H #<==顯示小時。
21
[[email protected] ~]# date +%M #<==顯示分。
01
[[email protected] ~]# date +%S #<==顯示秒。
25
[[email protected] ~]# date +%F #<==顯示特殊格式日期(年-月-日)。
2017-07-06
[[email protected] ~]# date +%T #<==顯示特殊格式時間(時:分:秒)。
21:03:08

範例8-46:通過參數-d顯示指定字符串所描述的時間的示例。


[[email protected] ~]# date +%F -d "-1day"       #<==顯示昨天(簡潔寫法)。
2017-07-05
[[email protected]ldboy ~]# date +%F -d "yesterday"   #<==顯示昨天(英文寫法)。
2017-07-05
[[email protected] ~]# date +%F -d "-2day"       #<==顯示前天。
2017-07-04
[[email protected] ~]# date +%F -d "+1day"       #<==顯示明天。
2017-07-07
[[email protected] ~]# date +%F -d "tomorrow"    #<==顯示明天(英文寫法)。
2017-07-07
[[email protected] ~]# date +%F -d "+2day"       #<==顯示2天后。
2017-07-08
[[email protected] ~]# date +%F -d "1month"      #<==顯示1個月後。
2017-08-06
[[email protected] ~]# date +%F -d "1year"       #<==顯示1年後。
2018-07-06
#<==說明:這裏的+號表示未來,-號表示過去,day表示日,year表示年,month表示月
[[email protected] ~]# date +%F -d "24hour"
2017-07-07
[[email protected] ~]# date +%F -d "1440min"
2017-07-07
[[email protected] ~]# date +%F -d "-1440min"
2017-07-05

說明:

這裏的hour表示小時,min表示分。

範例8-47:時間格式轉換例子。


[[email protected] ~]# date -d "Thu Jul  6 21:41:16 CST 2017" "+%Y-%m-%d %H:%M:%S"
2017-07-06 21:41:16

說明:

-d選項後面應接上需要轉化的時間,最後再接上你想要輸出的時間格式。

下面是一個企業面試題,要求轉換日誌的時間格式,解答該題會利用到上面的知識點,同時還會使用awk命令。

備用數據如下:


[[email protected] ~]# cat test.log 
Sat May 19 13:40:02 CST 2019 is 13213213
Sat May 19 19:37:43 CST 2019 is 1012122
Sat May 19 13:40:03 CST 2019 is 13213213
Sat May 19 19:37:42 CST 2019 is 1012122
Sat May 19 13:40:03 CST 2019 is 13213213
Sat May 19 19:37:43 CST 2019 is 1012122

解答過程如下:


[[email protected] ~]# awk -F "is" '{print "echo $(date -d \""$1"\" \"+%F %T \")",$2}' test.log
#<==對內容按照命令進行拼接。
echo $(date -d "Sat May 19 13:40:02 CST 2019 " "+%F %T ")  13213213
echo $(date -d "Sat May 19 19:37:43 CST 2019 " "+%F %T ")  1012122
echo $(date -d "Sat May 19 13:40:03 CST 2019 " "+%F %T ")  13213213
echo $(date -d "Sat May 19 19:37:42 CST 2019 " "+%F %T ")  1012122
echo $(date -d "Sat May 19 13:40:03 CST 2019 " "+%F %T ")  13213213
echo $(date -d "Sat May 19 19:37:43 CST 2019 " "+%F %T ")  1012122
[[email protected] ~]# awk -F "is" '{print "echo $(date -d \""$1"\" \"+%F %T \")",$2}' test.log|bash
2019-05-19 13:40:02 13213213
2019-05-19 19:37:43 1012122
2019-05-19 13:40:03 13213213
2019-05-19 19:37:42 1012122
2019-05-19 13:40:03 13213213
2019-05-19 19:37:43 1012122
#<==命令說明:使用is作爲分隔符,$1是「Sat May 19 13:40:02 CST 2019」,$2是「13213213」,首先使用date命令對原時間格式進行轉換,然後利用awk拼湊出如下格式,最後使用bash執行命令。

範例8-48:通過參數-s設定時間。


[[email protected] ~]# date -s 20170706              #<==設置成20170706,具體時間爲空即00:00:00。
Thu Jul  6 00:00:00 CST 2017
[[email protected] ~]# date -s 00:00:03               #<==設置具體時間,不會對日期做更改。
Thu Jul  6 00:00:03 CST 2017
[[email protected] ~]# date -s "00:00:03 20170706"    #<==這樣可以設置全部時間。
Thu Jul  6 00:00:03 CST 2017
[[email protected] ~]# date -s "00:00:03 2017-07-06"  #<==日期可使用不同的格式。
Thu Jul  6 00:00:03 CST 2017
[[email protected] ~]# date -s "00:00:03 2017/07/06"  #<==日期可使用不同的格式。
Thu Jul  6 00:00:03 CST 2017

8.6 本章重點

1)Linux中的文件類型知識。

2)重點要掌握的命令:which、find、xargs、tar、date。