find

张贺,多年互联网工作经验,担任过网络工程师、系统集成工程师、LINUX系统运维工程师,负责过大规模集群架构自动化运维管理工作,擅长Web集群架构与自动化运维,曾负责国内某电商运维工作。
笔者微信:zhanghe15069028807

locate

文件查找就是在文件系统上查找查找符合条件的文件。

linux对文件查找的方式有两种:非实时查找和实时查找,非实时查找就是只查找文件系统的索引 ,我们知道系统上所有的文件都是有索引的,我们可以把linux系统的索引理解为就是文件的目录,但是这个目录并不是你建立了文件然后立即更新的,它是有周期性的(定时或者是在系统不繁忙的时候),也就是说你刚才创建的文件,马上使用非实时查找的方式去查找是找不到的,因为它还没有来的及做索引,所以如果我们使用非实时查找的工具都查找刚创建的文件时,要首先把索引更新一下,使用”updatedb”命令即可更新,值得一提的是这个命令并不能随便用,如果你的服务器产生了成千上万的文件,还没来得更新索引,你使用updatedb命令手动更新一下的话,会非常占用资源,如果你服务器在你更新的时候正处于繁忙的状态下,很有可能宕机。

如:

[root@zhanghe ~]# locate zhanghe
/home/zhanghe
/home/zhanghe/.bash_logout
/home/zhanghe/.bash_profile
/home/zhanghe/.bashrc
/home/zhanghe/.gnome2
/var/spool/mail/zhanghe

当我们使用windows时,当我们打开我的电脑的时候,有的时候会很慢,在搜索框当中会出现进度条,其实这个时候就是在更新索引,那么怎样才能触发系统更新索引呢?windows和linux一样都是周期性的更新(定时、或者不繁忙的时候)。

FIND

语法

由于locate的种种弊端,我们经常使用的一般是find命令。

语法:find <在哪里找> <条件>

直接使用find命令什么也不带的话,相当于ls –a 列出所有的文件及目录

查找条件

文件名

-name “文件名称”,支持使用通配符,* ? [ ] [^]

-iname “文件名称”,不区分大小写,同样也支持通配符

-regex “正则表达式”,使用此选项可支持正则表达式 应重点掌握

[root@zhanghe ~]# find  /home  -name *.txt    -name
/home/zhanghe/zhanghe.txt

[root@zhanghe ~]# find /home  -iname *.txt -ls    -iname
17   1 -rw-r--r--  1 root   root   0 7月 30 03:36 /home/zhanghe/zhanghe.txt

[root@zhanghe ~]# find /home -regex ^.*.txt      -regex
/home/zhanghe/zhanghe.txt

[root@nginx ~]# find /etc -regex ".*tion$"
/etc/selinux/targeted/active/modules/100/application
/etc/selinux/targeted/active/modules/100/motion

属主和属组

-user USERNAME :查找属主为指定用户的文件
-group  GROUPNAME :查找属组为指定组的文件
-nouser 查找没有属主的文件
-nogroup查找没有属组的文件
[root@zhanghe ~]# find /home -user zhanghe   
/home/zhanghe
[root@zhanghe ~]# find /home -group zhanghe 
/home/zhanghe

[root@zhanghe ~]# useradd zhangjia;userdel zhangjia   #添加一个用户再删除
[root@zhanghe ~]# find /home –nouser -nouser
/home/zhangjia
/home/zhangjia/.bash_profile

[root@zhanghe ~]# find /home -nogroup -nogroup
/home/zhangjia
/home/zhangjia/.bash_profile

用户ID

如果我们删除了一个用户,那么原本属于这个用户的文件的所有人和所属组就没有了,只剩下id。如果还想要删除的话就得根据uid来查找删除,还是比较实用的。

  • -uid USERID:查找属主为指定UID号的文件

  • -gid GROUPID:查找属组为指定GID号的文件

[root@zhanghe ~]# id zhanghe
uid=500(zhanghe) gid=500(zhanghe) 组=500(zhanghe)

[root@zhanghe ~]# find /home -uid 500
/home/zhanghe
/home/zhanghe/.bash_profile

[root@zhanghe ~]# find /home -gid 500
/home/zhanghe
/home/zhanghe/.bash_profile

文件类型

-type [l|s|b|p|c|d]

f 普通文件
l 符号链接
d 目录
c 字符设备
b 块设备
s 套接字

[root@zhanghe ~]# find /bin -type l -ls
12058631   0 lrwxrwxrwx  1 root   root      4 6月 17 06:00 /bin/egrep -> grep
12058650   0 lrwxrwxrwx  1 root   root       3 6月 17 06:00 /bin/gtar -> tar

[root@zhanghe ~]# find /dev -type b
/dev/sda3
/dev/sda2
/dev/sda1

文件大小

文件大小和时间戳类似,可以使用数轴的方式进行记忆。

时间戳 文件大小
+3 四天之前 大于3K
3 3天前的一天,3天和4天之间 3K----2K之间
-3 3天以内 2K以内
[root@zhanghe ~]# find / -size -3k  大于0k小于2K
[root@zhanghe ~]# find / -size 3k   大于2k小于等于3K
[root@zhanghe ~]# find / -size +3k  大于3K

时间戳

以时间戳记忆的时候一定要结合文件大小进行记忆,两者相关联。

mtime是以天为单位

-mtime n :意义在在n天之前的“一天之内”被更改过过的因为有人
-mtime +n 列出在n天之前(不包含n天)被更改过的文件名
-mtime –n列出在n天之内(包含n天)被更改过的文件。

解析:

-4就代表在四天之内,当然是包括四天的,也就是小于等于四天。

而4就代表在四天之前,五天之内的

而+4就代表在是五天之前了,当然也包括五天,也就是大于等于5天。

权限

权限也有加减号之分,值得一提的是加号在centos7上面不再支持,仅支持负数和整数。

  • +MODE:任何一类(u,g,o)对象的权限中只要能一位匹配即可,有或者之意。

  • -MODE:每一类对象都必须同时拥有为其指定的权限标准,有并且之意。

对于+号的解释:来,来,来,:任何一类(u,g,o)对象的权限中只要能一位匹配即可,有或者之意举个例子:假如一个文件是的权限002的话,那么使用+002可以查找出来,使用+004不可以,因为004的最后一类的权限是4,而4仅仅代表的是读权限罢了,如果是+006就可以,因为+006最后一位是包括读和写,满足一项即可,所以002也满足。

如果文件的权限772,我们使用002也可以匹配到,因为最后一类的最后一位可以被002当中的2匹配到,再次强调,任何一类对象的当中的任意一位被包括即可,但是这个包括是对位的,假如说查看+666的话,满足这个条件的权限就有:200、400、020、222、002、220……442,420,240,444,都可以

[root@zhanghe ~]# find /etc -perm 644 -ls   #查找权限是644的文件
5767681  12 -rw-r--r--    10130 5月 12  2016 /etc/bash_completion.d/yum.bash
5768951   4 -rw-r--r--     1527 3月 26  2015 /etc/bash_completion.d/scl.bash
5768897   8 -rw-r--r--   2016 /etc/bash_completion.d/yum-utils.bash

[root@zhanghe ~]# find /etc -perm +600 -ls | tail  #属主能读**或者**能写即可,0表示忽略
5767999   0 -rw-r--r--   0 5月 11  2016 /etc/cups/lpoptions
5767996   4 **--w**-------  4064 5月 11  2016 /etc/cups/cupsd.conf
5767994   0 **–r-**-------  0 5月 11  2016 /etc/cups/classes.conf

[root@zhanghe ~]# find /etc -perm +222 -ls | tail  #任意一类拥有写权限即可
5767999   0 -rw-r--r--  1 root   lp        0 5月 11  2016 /etc/cups/lpoptions
5767996   4 -rw-r-----  1 root   lp      4064 5月 11  2016
5767994   0 -rw-------  1 root   lp        0 5月 11  2

[root@zhanghe ~]# find /etc/ -perm -644 -ls | tail   #权限里面必须包含644,只可多不可少
5768004   0 -rw-r--r--  1 root   lp        0 5月 11  2016
5768000   4 drwxr-xr-x  2 root   lp      4096 5月 11  2016 /etc/cups/ppd
5768002   4 -rw-r--r--  1 root   lp       186 5月 11  2016
5767999   0 -rw-r--r--  1 root   lp        0 5月 11  2016 /etc/cups/lpoptions
5767995   0 -rw-r--r--  1 root   lp        0 5月 11  2016 /etc/cups/client.conf
5767998   4 drwxr-xr-x  2 root   root     4096 5月 11  2016  #组合条件

-a 与
-o  或
! 非

[root@local zhanghe]# ls -l
-rw-r--r--. 1 root root   0 7月  30 04:09 a.txt   #一个普通文件
drwxr-xr-x. 2 root root 1024 7月  30 04:09 b.dir  #一个目录
lrwxrwxrwx. 1 root root  13 7月  30 04:09 zhanghe -> /home/zhanghe #一个软链接

[root@local ~]# find /tmp/zhanghe/ -type f -a -iname *.txt  #查找普通文件并是txt结尾
/tmp/zhanghe/a.txt

[root@local ~]# find /tmp/zhanghe/ -type f -o -type d   #查找普通文件或者目录
/tmp/zhanghe/
/tmp/zhanghe/a.txt
/tmp/zhanghe/b.dir

[root@local ~]# find /tmp/zhanghe/ -type f ! -type l –ls  #查找非-=普通文件,非链接文件
  15   1 -rw-r--r--  1 root   root       0 7月 30 04:09 /tmp/zhanghe/a.txt

处理动作

-print :默认的处理动作,显示至屏幕

-ls:类似于对查找到的文件执行ls –l命令

-delete:删除查找到的文件

-fls /PATH/TO/SOMFILE查找到的所有文件的长格式信息保存到指定文件中

-ok COMMND {} ; 对查找到的每个文件执行由COMMAND指定的命令

对于每个文件执行命令之前,都会交互要求用户确认

-exec COMMAND {} ; 对查找到的文件执行由COMMAND指定的命令

注意:find传递查找到的文件至后面指定的命令时,查找到所有符合条件的文件一次性传递给后面的命令;有些命令不能授受过多的参数,此时命令执行可能会失败,另一个方式可规避此问题:

find | xargs COMMAND
[root@zhanghe ~]# find /tmp -perm +400 –ls  
[root@zhanghe ~]# find /tmp -perm +400 –delete      #操作要小心
[root@zhanghe ~]# find /tmp -perm  +400 -exec ls -lh {} ;  #注意格式
drw-r--r--. 2 root root 1.0K 7月  30 21:45 a.txt
drwx------. 2 root root 1.0K 7月  30 21:46 b.txt
[root@zhanghe ~]# find /tmp -perm  +400 -ok ls -lh {} ;    #注意格式
< ls ... /tmp > ? y   #会询问
总用量 4.0K
drw-r--r--. 2 root root 1.0K 7月  30 21:45 a.txt
drwx------. 2 root root 1.0K 7月  30 21:46 b.txt
[root@zhanghe ~]# find /usr -perm +400 -fls /tmp/zhanghe.txt
[root@zhanghe ~]# find /usr -perm +400 | xargs+ ls -ldh | tail
drwxr-xr-x.  2 0  0 4.0K 9月  23 2011 /usr/src/debug

练习

查找/etc目录下以tions结尾的目录或者文件然后把其详细信息保存到/tmp/下的test.txt文件下

[root@China ~]# find /etc -regex ".*tions$" -fls /tmp/test.txt

查找/etc/下大于5M的文件或目录并显示其详细信息。

[root@China ~]# find /etc -size +5M -exec ls -lh {} ;
-rw-r--r--. 1 root root 8.1M 6月  17 06:05 /etc/selinux/targeted/modules/active/policy.kern
-rw-r--r--. 1 root root 8.1M 6月  17 06:05 /etc/selinux/targeted/policy/policy.24

查看/etc下小于1M的文件或目录删除之

[root@China ~]# find /etc -size -2 -exec rm –rf {} ;
[root@China ~]# find /etc -size -2 –delete    #其实可以更简单

查找/var目录下属主为root,且属组为mail的所有文件或目录

find /var –user root –a –group mail

查找/usr目录下不属于root、bin、.或hadoop的所有文件或目录

find /usr –not –user root –a –not –user bin –a –not –user hadoop

查找/etc目录一点点最近一周内容被修改过,同时属主不为root和hadoop的文件或目录

find /etc –mtime -7 –a –not –user root –a –not –user hadoop

查找当前系统没有属主且没有属组,最近一个周内被访问过的文件或目录

find / -nouser –a –nogroup –a –atime -7  

查找/etc/目录下大于1M且类型为普通文件的文件或目录

find /etc –size +1M –a –type f

查找/etc目录下所有用户都没有写权限的文件

find /etc/  -not -perm +222   #如不加not为仅满足一个2即可,加上not就是一个2都不能满足。

查找/etc/init.d目录下,所有用户都有执行权限,且其它用户有写权限的文件

find /etc/init.d –perm -113

查看/etc/目录下,修改时间是三天前的文件或目录

find /etc –mtime +3

解析:做上面这个题是纠结的,如果是把三天前理解成为3天之前不包括三天的话使用+3是对的,因为+3意思着大于等于4天;如果把前三天理解成为3天前包括三天的话就得使用+2,因为+2代表大于等于3天。

假如当天是2010年1月5日,我想要查找1月3日创建哪些文件?

[root@China ~]# date 010300002010
2010年 01月 03日 星期日 00:00:00 CST
[root@China ~]# touch /tmp/test.txt
[root@China ~]# stat /tmp/test.txt|grep "Change"
Change: 2010-01-03 00:00:21.000000000 +0800
[root@China ~]# date 010500002010
2010年 01月 05日 星期二 00:00:00 CST
[root@China ~]# find /tmp -ctime +2|grep test.txt #没有查找到
[root@China ~]# find /tmp -ctime +1|grep test.txt
/tmp/test.txt     #成功查找到

解析一下,今天是3号,我创建一个文件test.txt,然后我把时间改为5号。我想要查找到3号创建什么文件,+2表示大于等于3天,也就是三天前,对于当前时间(5号)来说,算上5号这一天的话,大于等于3天指2号那天或者是2号之前创建的文件,所以并没有找到;当我反条件改成+1的话,也就是大于等于2,对于当前的时间(5号)来说,大于等于2天也就是在3号的那天或者是在3天之前,文件正好是3号创建的,所以正好可以查找到。

假如当天是2010年1月5日,我想要查找3天之内创建哪些文件?

[root@China ~]# stat /tmp/test2.txt
Change: 2010-01-02 00:00:09.000000000 +0800
[root@China ~]#  date 010500002010
2010年 01月 05日 星期二 00:00:00 CST
[root@China ~]# find /tmp -ctime -3
/tmp/test.txt         #并不能查找到新创建的那个test2.txt文件

解析:-3代表大于大于等于0小于3,也就是说当天或者3,4,5号的任意一天都会被查找到,并不包括2号的那天,为什么?因为是大于等于0小于3,并不是等于3,所以不包括2号。

由此我们总结一下:

如果按照天数查找:

如果让我们查看一下在3天内修改的文件使用-3即可

如果让我们查看一下在3天前修改的文件使用+2即可

如果按照文件大小查找:

大于3M就是+3

小于3M就是-4

如果按照权限查找:

所有都包括某个权限使用减号

仅一项包括使用+号

完全匹配什么号也不加

xargs与exec

面试题

今天去同学公司的时候,和他们人事聊了聊,看到了桌子上的面试题,有一道题很有意思,一共有三份试题,来了三个人面试,两个人写错了,其中一个没回答上来,我也是无语了,就这水平,还出来面试,听人事说口气还大的很,不知道从哪里来的自信?不知道他们是昨学的?

面试题是这样:

请找出/test.dir目录下的文件名中包含test关键字的文件并将其全部删除(注:不少于两种方法)

有两位面试者都是这么写的:

find ./ -name "*test*" -type f | rm –rf

img

这么写看上去是没错的,但实际的操作肯定不行的,还是太嫩了!

img

为什么这么操作不行呢?find向外输出的是什么?我们是按照文件名查找的,找到的其实就文件名组成的字符流,你把一个字符流通过管道传送给rm命令,rm自然会正常的执行,但是这个字符流与文件路径没有关系,这样删除的只是find的查看后的结果,所以就无法删除,那么要怎么做才行能删除呢?只要将FIND查找到的字符流转换成路径就行了,这样方法就多了,我们可以通过find自带的exec或者借助xargs命令将字符流转换为真实的路径就行了,我们来尝试一下:

[root@localhost ~]# mkdir test.dir ; cd test.dir
[root@localhost test.dir]# touch test_{01..06}.txt 
[root@localhost test.dir]# ls test_01.txt  test_02.txt  test_03.txt  test_04.txt  test_05.txt  test_06.txt 
[root@localhost test.dir]# find ./ -name "*test*" -type f | xargs rm -rf 
[root@localhost test.dir]# ls  #空的

再来尝试另一种办法,这种方法是find自带的,效果和上面的例子是一样的。

[root@localhost test.dir]# ls test_01.txt  test_02.txt  test_03.txt  test_04.txt  test_05.txt  test_06.txt
[root@localhost test.dir]# find . -type f -name "*test*" -exec rm -f {} ;
[root@localhost test.dir]# ls

再来一种更加简单粗暴的方法:

[root@localhost test.dir]# rm -rf `find ./ -name "*test*" -type f`
[root@localhost test.dir]# ls #空的

我们再来举一个例子体会一下:

[root@localhost test.dir]# ls test_01.txt  test_02.txt  test_03.txt  test_04.txt  test_05.txt  test_06.txt
[root@localhost test.dir]# echo testtesttest > test_01.txt 
[root@localhost test.dir]# echo testtesttest > test_02.txt   #除了这两个文件之外都是空的
[root@localhost test.dir]# find -name "*.txt" | rm -rf    #我们已经知道,这样肯定是无法删除这些文件的。
[root@localhost test.dir]# ls test_01.txt  test_02.txt  test_03.txt  test_04.txt  test_05.txt  test_06.txt    #果不其然
[root@localhost test.dir]# find -name "*.txt" | grep test  #这个操作很正常,将文件名里面包含test的文件都过滤出来了 
./test_01.txt ./test_02.txt ./test_03.txt ./test_04.txt ./test_05.txt ./test_06.txt [root@localhost test.dir]# find -name "*.txt" | xargs grep test ./test_01.txt:testtesttest ./test_02.txt:testtesttest
#重要的是这里,加一个xargs,grep就不是在文件名里面找了,而是找文件里面找了!!! 

仔细体会一下,体会到了吗?好了,我来总结一下吧!

如果没有xargs的话,grep只会把find的结果当做是字符流,并不是将其当做是文件,当有了xargs之后,这些字符流就变成了真正的路径,其实将xargs换成find自带的exec也是可以的,如下所示:

[root@localhost test.dir]# find -name "*.txt" -exec  grep test {} ;  #{}就是指前面find的结果,标准输出嘛! testtesttest testtesttest

两个例子

请找出/test.dir目录下的文件名中包含test关键字的文件并将其全部移动到/tmp目录(注:不少于两种方法)

如何操作呢?

img

第一种方式:

[root@localhost test.dir]# ls test_01.txt  test_02.txt  test_03.txt  test_04.txt  test_05.txt  test_06.txt
[root@localhost test.dir]# mv `find -name "*test*" -type f` /tmp    #将命令放置到``当中,自动就能将流转换成有意义的路径

第二种方式:

[root@localhost test.dir]# ls test_01.txt  test_02.txt  test_03.txt  test_04.txt  test_05.txt  test_06.txt
[root@localhost test.dir]# find -name "*test*" -type f -exec mv <----写到这里就写不下去了!

#mv的语法是这样的:mv <被移动的文件> <目标文件夹>,但是这里find会将结果补全到最后也就是<目标文件夹>的位置,怎么办?

#exec是不能用了,我们可以这样,如下所示:

[root@localhost test.dir]# find -name "*test*" -type f | xargs mv -t /tmp

#xargs我们已经理解了,那-t是什么意思?mv -t的意思就是将<被移动的文件>和<目标文件夹>换一下位置,这样find的结果就正好补全到<被移动的文件>,这不就完美了!

第三种方式:

第三种方式与第二种方式差不多,不过我们不用mv的-t选项了,而使用xargs自带的机制了,如下所示:

[root@localhost test.dir]# find -name "*test*" -type f | xargs -i mv {} /tmp;

#这次我们没有改变mv的语法,只是用中括号代替了<被移动的文件>,不要忘了xargs前面要加一个-i的选项,只有这样中括号才有意义!

题目2

请找出/test.dir目录下的文件中包含test关键字的文件并将其全部复制到/tmp目录(注:不少于两种方法)

如何操作呢?

[root@localhost test.dir]# find ./ -name "*test*" -type f | xargs -i cp {} /tmp;
[root@localhost test.dir]# find ./ -name "*test*" -type f | xargs cp -t /tmp;
[root@localhost test.dir]# cp `find ./ -name "*test*" -type f` /tmp

我打字累了,不解释了,第一个题目看懂后,这一个题目看懂自然不成问题!!!

现在,我真想大声对那三个面试者说:

img

哈哈!

我们在使用find的时候一定要注意,find的查询范围要界面小一些,如果直接从根直接查找的话容易把内存给打满,一旦内存满了之后就容易触发系统的保护机制,会随机杀死一个占用内存最高的进程,如果系统中运行着mysql,系统很容易会将其干掉!!!

原文地址:https://www.cnblogs.com/yizhangheka/p/12054263.html