linux每日命令(22):find命令参数详解

2018-12-13 16:36:17 浏览数 (1)

一. name选项

文件名选项是find命令最常用的选项,要么单独使用该选项,要么和其他选项一起使用。 可以使用某种文件名模式来匹配文件,记住要用引号将文件名模式引起来。 不管当前路径是什么,如果想要在自己的根目录$HOME中查找文件名符合*.log的文件,使用~作为 'pathname'参数,波浪号~代表了你的$HOME目录。

代码语言:javascript复制
find ~ -name "*.log" 

想要在当前目录及子目录中查找所有的‘ *.log‘文件,可以用:

代码语言:javascript复制
find . -name "*.log" 

想要的当前目录及子目录中查找文件名以一个大写字母开头的文件,可以用:

代码语言:javascript复制
find . -name "[A-Z]*" 

想要在/etc目录中查找文件名以host开头的文件,可以用:

代码语言:javascript复制
find /etc -name "host*" 

想要查找$HOME目录中的文件,可以用:

代码语言:javascript复制
find ~ -name "*" 

要想让系统高负荷运行,就从根目录开始查找所有的文件。

代码语言:javascript复制
find / -name "*" 

如果想在当前目录查找文件名以一个个小写字母开头,最后是4到9加上.log结束的文件:

命令:

代码语言:javascript复制
find . -name "[a-z]*[4-9].log" -print

二. perm选项

代码语言:javascript复制
按照文件权限模式用-perm选项,按文件权限模式来查找文件的话。最好使用十进制的权限表示法。
如在当前目录下查找文件权限位为755的文件,即文件属主可以读、写、执行,其他用户可以读、执行的文件,可以用:

 find . -perm 755 

find -perm,根据文件的权限来查找文件,有三种形式: find -perm mode find -perm -mode find -perm mode

那么这三者之间有什么区别呢?解释之前首先得简单说一下linux中文件权限位的概念。在linux中文件或目录有三者权限r,w,x,代表的含义分别是读、写、可执行。而一个文件或目录的属性中又包括所属用户u、所属组g、其他o三个部分的属性,分别表示所属用户、所属组、其他用户对这个文件所拥有的权限。看起来大概是这个样子: 所属用户 所属组 其他 rwx rwx rwx

用户在其拥有权限的位上设置1,没有权限的位设置0。如果将每个部分的这些权限位看成二进制数,每个部分可以用3位二进制数表示,最大值为7(2^3-1),表示可读、可写、可执行。严格的来说,文件权限除了r、w、x以外还有setuid,setgid权限,等下再解释。 好了,有了权限位的基础,那么再来看find -perm mode。mode是三个数字表示的,每个数字最大值是7(原因前面解释过了)。 find -perm mode , 表示严格匹配,也就是你的文件权限位转换成对应的十进制数字与mode一模一样,那么匹配成功,需要注意的是如果mode给的数字不足3位,那么前面自动添0(严格的说是不足4位,原因就是前面所说的setuid,setgid,稍后解释)

find -perm -mode , 表示mode中转换成二进制的1在文件权限位里面必须匹配,比如mode=644那么转换成二进制为110 100 100,而被查找的文件的权限位也可以被转换成一个二进制数,两者在位上为1的部分必须完全匹配,而0则不管。例如被查找的文件的权限为转换成二进制数是111 111 111那么这个比如被匹配,而假如是100 100 100那么则不会匹配。所以这个'-'的作用归结起来就是匹配比mode权限更充足的文件(找不到什么词语来形容了)

find -perm mode , 与 -mode的区别是 mode只需其中的任意一个1的部分被匹配,-mode是所有1的部分都必须被匹配,同样 mode也不管0位。

现在来解释setuid,setgid,setuid权限是用来使其他用户可以“越权”执行你的命令,而本质上的实现就是在权限检查的时候,在进程的的有效UID里面保存了这个其他用户的UID,所以权限得意验证通过(在这里的 http://www.2cto.com/os/201205/130111.html 注释1里面很简单的介绍了一下),这些权限用一个新的3位二进制数表示,有4,2,1三种值,4表示有setuid权限,2表示有setgid权限,1表示有粘着位(t)权限(粘着位权限最典型的例子是/tmp,每个用户可以在里面创建、更新、删除自己创建(文件所属用户是自己)的文件,而不能更改别人的文件)。

代码语言:javascript复制
$ ls -l 
total 0
-rwxrwxrwx 1   fai     root       0 Aug 28 15:15 a
-rwxr-xr-x    1   fai     root       0 Aug 28 15:15 b
----rw----     1   fai     root       0 Aug 28 15:15 c
-rw-rw-rw-  1   fai     root       0 Aug 28 15:15 d
-r-xr--r--      1   fai     root       0 Aug 28 15:15 e

对于权限进行十进制转2进制 a(777):111 111 111 b(755):111 101 101 c(060): 000 110 000 d(666):110 110 110 e(544):101 100 100

代码语言:javascript复制
$ find . -perm  006
.
./b
./d
./a
./e

mode中的006转为2进制是:000 000110 根据部分匹配的原则,只要在第3组中的第一或者第二位出现1就可以了,所以看到e文件101只是匹配了第一位的1,但是也打印了。而a文件111的情况更是符合这个说法了。注意:c文件虽然出现了110,但是不是对应的组,这个匹配是在相应位的。

代码语言:javascript复制
$ find . -perm -006
./d
./a

对于-perm -006,也同样道理去判断,只是这里需要完全匹配,也就是mode的二进制中出现1的地方,目标中也要出现才行 需要在最后一组中的第一和第二位同时出现1才能匹配。 a(777):111 111 111 d(666):110 110 110

三. prune选项(此处引用http://blog.sina.com.cn/s/blog_6ad648f30100tqwy.html)

查找时忽略指定目录,是要使用-prune选项,但实际上最重要的还是要和path配合。-prune的意义是,当路径字串匹配了path中指定的目录时 候,find命令不进入这个目录查找,所以这个选项使用的关键,还是在path选项上的使用,也就是path选项和其他选项的配合使用,才能最后确定最终 结果。而path,实际上是对路径字串的一个字符匹配,但也并不仅仅只匹配于目录,文件同样可以被匹配,譬如存在一个目录结构。

代码语言:javascript复制
./01.txt
./02.txt
./03.txt
./aaa
./aaa/04.txt
./aaa/05.txt

find . -path "./aaa" -print 匹配中使用通配符,则会输出

代码语言:javascript复制
./aaa
./aaa/04.txt
./aaa/05.txt

而如果是find . -path "./aaa" -print ,严格等于./aaa目录,则只输出

./aaa

而且*通配符会将路径中的字符"/"也作为普通字符进行贪婪匹配,所以可以匹配到目录以下的文件,所以在使用这个选项时候不要误以为这个只对目录有效,实际上只是一种路径字符匹配工具。

1.查找文件时,忽略某个目录

如果加上-prune,则第一个命令效果是:

代码语言:javascript复制
find . -path "./aaa*" -prune -print

./aaa

因为加入了-prune,在匹配这个目录同时禁止进入到这个目录下搜索,于是也就是我们所需要的不进入某个目录查找。

但如何配合其他选项来使用-path 以及-prune呢?以-name为例,下面对于配合使用方法进行一下演示。

我们先来看看纯粹的-name和-path配合使用是什么效果:

代码语言:javascript复制
find -name "*.txt" -path "./aaa" -print

这个命令也相当于

代码语言:javascript复制
find -name "*.txt" -a -path "./aaa" -print

但一般的-a都被忽略不写。这个命令对于上面的目录结构这个命令执行为空结果。也就是,既要文件名称匹配".txt",同时又要其路径字 串匹配"./aaa",而文件名匹配".txt"的结果有:

代码语言:javascript复制
./01.txt
./02.txt
./03.txt
./aaa/04.txt
./aaa/05.txt

路径字串匹配 "./aaa"的只有 ./aaa 二者取and则为空结果,所以上面的命令输出为空。

如果对-path选项加上-prune

代码语言:javascript复制
find -name "*.txt" -path "./aaa" -prune -print

实际上与上面那条命令输出并无区别,只是禁止进入./aaa下匹配而已,但最终的结果仍然是空。

再来看看很多人会误用的结构:

代码语言:javascript复制
find -name "*.txt" -path "./aaa" -prune -o -print

也就是比上一条语句在-print前增加一个-o。但实际上这条命令是将当前目录以及包含./aaa子目录下的所有文件都打印出来。实际上 ,这个语句先执行-o左侧的语句,find -name "*.txt" -path "./aaa" -prune,因为匹配为空,则执行-o右侧的语句-print,也就是把不匹配左侧的文件名打印出来,既然左侧没有匹配为真的,所以也就是所有的文件都被打印。

这里要留意的是匹配模式项(比如-name "*.txt", -path ....),关系符( -a, -o, ","),与操作符(-print, -exec,- ok)之间的位置关系,特别是操作符在关系符的不同位置上,对于结果也具有决定的作用。

说明:

find [-path ..] [expression]

在路径列表的后面的是表达式

-path "test" -prune -o -print 是 -path "test" -a -prune -o -print 的简写表达式按顺序求值, -a 和 -o 都是短路求值,与 shell 的 && 和 || 类似如果

-path "test" 为真,则求值 -prune , -prune 返回真,与逻辑表达式为真;否则不求值 -prune,与逻辑表达式为假。如果 -path "test" -a -prune 为假,则求值 -print ,-print返回真,或逻辑表达式为真;否则不求值 -print,或逻辑表达式为真。

这个表达式组合特例可以用伪码写为:

if -path "test" then

-prune

else

-print

比如一个语句

代码语言:javascript复制
find -name "*.txt" -print -o -path "./aaa" -prune -print             (1)

其实也可以略写为

代码语言:javascript复制
find -name "*.txt" -o -path "./aaa" -prune

注意第二个语句-o两侧都没有-print,输出结果为:

代码语言:javascript复制
./01.txt
./02.txt
./03.txt
./aaa    

这是因为find开始执行,遇到第一个-print命令,则会考虑输出,但是输出的时候,则是将剩余所有的匹配项一起进行匹配操作,也就是执行的是

代码语言:javascript复制
find -name "*.txt" -print -o -path "./aaa" -prune  (注意-print命令的位置)

这个命令执行中相当于

代码语言:javascript复制
find -path "./aaa" -prune -o -name "*.txt" -print

也 就是在匹配过程中,对于包含了-print部分的匹配项是最后匹配的,因此先匹配到了./aaa路径,由于-prune的存在禁止进入这个路径查找,禁止 进入查找,并不会因为-o选项而被逆转,所以左侧匹配了./aaa后,-o右侧则是不匹配./aaa项目剩余的文件继续去匹配-name模式,匹配的结果 最后被-print打印出来,这也就是我们所期待的忽略某个指定目录进行搜索的结果。

但是我们要分析的是命令(1)中的结果,命令(1)在遇到第一个-print命令后并执行了输出,但是这个find命令中还存在第二个-print命令,所以在输出

代码语言:javascript复制
./01.txt
./02.txt
./03.txt

结果后,还是要继续执行,要执行最后一个-print命令,下面的执行则相当于执行一个

代码语言:javascript复制
find -name "*.txt" -o -path "./aaa" -prune -print

-o左侧匹配-name "*.txt",-o到右侧后则是对不能匹配到-name模式的结果,进行-path匹配,输出结果为 ./aaa 所以(1)命令最终的输出结果就是

代码语言:javascript复制
./01.txt
./02.txt
./03.txt
./aaa 。

2. 忽略多个文件夹

-a, -o都常见了,但是实际中还可以存在“,“的使用,例如新建一个aaa1目录,其下有08.txt等文件,若执行

代码语言:javascript复制
$ find -name "*.txt"
代码语言:javascript复制
./01.txt
./02.txt
./03.txt
./aaa/04.txt
./aaa/05.txt
./aaa1/08.txt
./aaa1/09.txt

若忽略aaa和aaa1目录查找txt文件,则可以写做

代码语言:javascript复制
$ find -name "*.txt" -print -o -path "./aaa" -prune , -path "./aaa1"  -prune  (注意","两侧的空格不可忽略)
代码语言:javascript复制
./01.txt
./02.txt
./03.txt

这也就是同时忽略几个目录的写法,注意每忽略一个目录,其后都要跟随一个-prune,而不能几个-path公用一个-prune。

其实若没有-prune的使用,也可以忽略某个目录下文件的匹配,譬如

代码语言:javascript复制
$find -path "./aaa*" -o -name "*.txt" -print
代码语言:javascript复制
./01.txt
./02.txt
./03.txt

同样可以不匹配到./aaa目录下的文件,但是这里实际上是搜索过./aaa目录下的文件并且进行匹对的,只是因为-print在-o的右侧输出,而./aaa下的文件被匹配是在-o的左侧,所以最终的结果是达不到被打印输出的条件。但效率应当是明显低于使用-prune选项。

四. user和nouser 选项

1. 在$HOME目录中查找文件属主为hc的文件

代码语言:javascript复制
find ~ -user hc -print

2. 在/etc目录下查找文件属主为hc的文件:

命令:

代码语言:javascript复制
find /etc -user hc -print  

3. 为了查找属主帐户已经被删除的文件,可以使用-nouser选项。在/home目录下查找所有的这类文件

代码语言:javascript复制
find /home -nouser -print

说明:

这样就能够找到那些属主在/etc/passwd文件中没有有效帐户的文件。在使用-nouser选项时,不必给出用户名; find命令能够为你完成相应的工作。

五.使用group和nogroup选项:

就像user和nouser选项一样,针对文件所属于的用户组, find命令也具有同样的选项,为了在/apps目录下查找属于gem用户组的文件,可以用:

代码语言:javascript复制
find /apps -group gem -print  

要查找没有有效所属用户组的所有文件,可以使用nogroup选项。下面的find命令从文件系统的根目录处查找这样的文件:

代码语言:javascript复制
find / -nogroup -print

六.按照更改时间或访问时间等查找文件:

如果希望按照更改时间来查找文件,可以使用mtime,atime或ctime选项。如果系统突然没有可用空间了,很有可能某一个文件的长度在此期间增长迅速,这时就可以用mtime选项来查找这样的文件。

用减号-来限定更改时间在距今n日以内的文件,而用加号 来限定更改时间在距今n日以前的文件。

希望在系统根目录下查找更改时间在5日以内的文件,可以用:

代码语言:javascript复制
find / -mtime -5 -print

为了在/var/adm目录下查找更改时间在3日以前的文件,可以用:

代码语言:javascript复制
find /var/adm -mtime  3 -print

七.查找比某个文件新或旧的文件:

如果希望查找更改时间比某个文件新但比另一个文件旧的所有文件,可以使用-newer选项。

它的一般形式为:

代码语言:javascript复制
newest_file_name ! oldest_file_name  

其中,!是逻辑非符号。

1.查找更改时间比文件log1新但比文件log3旧的文件

命令:

代码语言:javascript复制
find -newer log1  ! -newer log3

2.查找当前目录下更改时间在比log2文件新的文件

命令:

代码语言:javascript复制
find . -newer log2  -print

八.使用type选项:

1:在/etc目录下查找所有的目录

命令:

代码语言:javascript复制
find /etc -type d -print  

2:在当前目录下查找除目录以外的所有类型的文件

命令:

代码语言:javascript复制
find . ! -type d -print  

3:在/etc目录下查找所有的符号链接文件

命令:

代码语言:javascript复制
find /etc -type l -print

九.使用size选项:

可以按照文件长度来查找文件,这里所指的文件长度既可以用块(block)来计量,也可以用字节来计量。以字节计量文件长度的表达形式为N c;以块计量文件长度只用数字表示即可。

在按照文件长度查找文件时,一般使用这种以字节表示的文件长度,在查看文件系统的大小,因为这时使用块来计量更容易转换。

1:在当前目录下查找文件长度大于1 M字节的文件

命令:

代码语言:javascript复制
find . -size  1000000c -print

2:在/home/apache目录下查找文件长度恰好为100字节的文件:

命令:

find /home/apache -size 100c -print

3:在当前目录下查找长度超过10块的文件(一块等于512字节)

命令:

代码语言:javascript复制
find . -size  10 -print

十.使用depth选项:

在使用find命令时,可能希望先匹配所有的文件,再在子目录中查找。使用depth选项就可以使find命令这样做。这样做的一个原因就是,当在使用find命令向磁带上备份文件系统时,希望首先备份所有的文件,其次再备份子目录中的文件。

1:find命令从文件系统的根目录开始,查找一个名为CON.FILE的文件。

命令:

代码语言:javascript复制
find / -name "CON.FILE" -depth -print

说明:

它将首先匹配所有的文件然后再进入子目录中查找

十一.使用mount选项:

在当前的文件系统中查找文件(不进入其他文件系统),可以使用find命令的mount选项。

1:从当前目录开始查找位于本文件系统中文件名以XC结尾的文件

命令:

代码语言:javascript复制
find . -name "*.XC" -mount -print

0 人点赞