zoukankan      html  css  js  c++  java
  • linux之find命令详解

    一、find概述

    话不多说,先来find --help一下

    [hive@lgh test]$ find --help
    Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression] #使用的语法
    
    default path is the current directory; default expression is -print #默认是当前目录,默认采用的action是-print,如果有设置action,则默认会被覆盖
    expression may consist of: operators, options, tests, and actions:
    
    operators (decreasing precedence; -and is implicit where no others are given): #一些重要操作,就像编程里面所用到的,与,非,或这些关系,
          ( EXPR )   ! EXPR   -not EXPR   EXPR1 -a EXPR2   EXPR1 -and EXPR2
          EXPR1 -o EXPR2   EXPR1 -or EXPR2   EXPR1 , EXPR2
    
    positional options (always true): -daystart -follow -regextype #总是返回true
    
    normal options (always true, specified before other expressions): #总是返回true
          -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf
          --version -xdev -ignore_readdir_race -noignore_readdir_race
    
    tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N   #重点
          -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME
          -ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN
          -links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE
          -nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN
          -readable -writable -executable
          -wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N
          -used N -user NAME -xtype [bcdpfls]
          -context CONTEXT
    
    
    actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print  #重点
          -fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit
          -exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;
          -execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;
    
    Report (and track progress on fixing) bugs via the findutils bug-reporting
    page at http://savannah.gnu.org/ or, if you have no web access, by sending
    email to <bug-findutils@gnu.org>.

    从上看:find命令的使用语法:

    Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

    其中expression主要包括operators, options, tests, and actions

    expression may consist of: operators, options, tests, and actions:

    二、find基本原理和实践

    find是从左向右处理的,所以表达式的前后顺序不同会造成不同的搜索性能差距。

    搜索机制:find的搜索机制是根据表达式返回的true/false决定的,每搜索一次都判断一次是否能确定最终评估结果为true,只有评估的最终结果为true才算是找到。

    find首先对整个命令行进行语法解析,并应用给定的options,然后定位到搜索路径path下开始对路径下的文件或子目录进行表达式评估或测试,评估或测试的过程是按照表达式的顺序从左向右进行的(此处不考虑操作符的影响),如果最终表达式的表达式评估为true,则输出(默认)该文件的全路径名

    2.1、操作符(operators)

        我相信大家都学过一些编程语言,这里的运算操作符合java中的编程语言一样的意思,其实就是一些与,或,非的操作,都是一些短路的操作,虽然比较简单,但是很有用,接下来我们具体看下这些内容:

    (expr)           #优先级最高。为防止括号被shell解释(进入子shell),所以需要转义,即(...)
    ! expr           #对expr的true和false结果取反。同样需要使用引号包围
    -not expr        #等价于"! expr"
    expr1 expr2      #等同于and操作符。
    expr1 -a expr2   #等同于and操作符。
    expr1 -and expr2 #首先要求expr1为true,然后expr2以expr1搜索的结果为基础继续检测,然后再返回检测值为true的文件。因为expr2是以expr1结果为基础的,所以如果expr1返回
                     #false,则expr2直接被忽略而不会进行任何操作
    expr1 -o expr2   #等同于or操作符
    expr1 -or expr2  #只有expr1为假时才评估expr2。
    expr1 , expr2    #逗号操作符表示列表的意思,expr1和expr2都会被评估,但expr1的true或false是被无视的,只有expr2的结果才是最终状态值。
    [hive@lgh test]$ ll
    total 8
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 a
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:06 c
    lrwxrwxrwx 1 hive hive    1 Sep 30 10:08 d -> a
    [hive@lgh test]$ find . -type f -a -name c  #打印文件,并且名为c  
    ./c
    [hive@lgh test]$ find . -type f -o -type d  #打印文件或者目录
    .
    ./a
    ./b
    ./c

    注意:and 的优先级高于 or,and和or操作都是短路操作,先判断第一个条件,and:如果第二个条件不满足,则第二个条件不予判读,or则相反

    2.2、选项(options)

         options总是返回true。除了"-daystart",options会影响所有指定的test表达式部分,哪怕是test部分写在options的前面。这是因为options是在命令行被解析完后立即处理的,而test是在检测到文件后才处理的。对于"-daystart"这个选项,它们仅仅影响写在它们后面的test部分,因此,建议将任何options部分写在expression的最前面。

    -daystart         #指定以每天的开始(凌晨零点)计算关于天的时间,用于改变时间类(-amin,-atime,-cmin,-ctime,-mmin和-mtime)
                      #的计算方式。默认天的计算是从24小时前计算的。例如,当前时间为5月3日17:00,要求搜索出2天内修改过的文件,默认
                      #搜索文件的起点是5月1日17:00,如果使用-daystart,则搜索文件的起点是是5月1日00:00。
                      #注意,该选项只会影响写在它后面的test表达式。
    -depth            #搜索到目录时,先处理目录中的文件(子目录),再处理目录本身。对于"-delete"这个action,它隐含"-depth"选项。
    -maxdepth levels  #指定tests和actions作用的最大目录深度,只能为非负整数。可以简单理解为目录搜索深度,但并非如此。当
                      #前path目录的层次为1,所以若指定-maxdepth 0将得不到任何结果。
    -mindepth levels  #tests和actions不会应用于小于指定深度的目录,"-mindepth 1"表示应用于所有的文件。
    -ignore_readdir_race #当无法用stat检测文件信息时(如无权限)会给出下图所示的错误信息,如要忽略该信息,可以使用该选项。

    [root@lgh ~]# find /etc -name passwd
    /etc/passwd
    /etc/pam.d/passwd
    [root@lgh ~]# find /etc -maxdepth 1 -name passwd
    /etc/passwd
    [root@lgh ~]#
    [root@lgh ~]# find /etc -maxdepth 2 -mindepth 2 -name passwd  #之返回第二层目录的匹配文件
    /etc/pam.d/passwd

    如果指定了-depth,则先处理目录中的文件,再处理目录本身。在Linux一切皆文件,子目录也是文件
    [hive@lgh test]$ ll total
    8 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 1.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 2.bak -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 3.bak drwxrwxr-x 2 hive hive 4096 Sep 30 10:52 a drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b -rw-rw-r-- 1 hive hive 0 Sep 30 10:06 c lrwxrwxrwx 1 hive hive 1 Sep 30 10:08 d -> a [hive@lgh test]$ find ../test -depth ../test/3.bak ../test/a/1.txt ../test/a/2.txt ../test/a/3.txt ../test/a #先处理目录a下的文件,才处理a目录 ../test/1.bak ../test/b ../test/2.bak ../test/c ../test/d ../test #最后才处理目录

    2.3、tests

    (N can be +N or -N or N)
    +n:大于n
    -n:小于n
    n :精确的等于n

    2.3.1、从文件类型判断

    -type [bcdpflsD] 

    X  #根据文件类型来搜索 
    b  #块设备文件
    c  #字符设备文件
    d  #目录
    p  #命名管道文件(FIFO文件)
    f  #普通文件
    l  #符号链接文件,即软链接文件
    s  #套接字文件(socket)
    [hive@lgh test]$ ll
    total 8
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 a
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:06 c
    lrwxrwxrwx 1 hive hive    1 Sep 30 10:08 d -> a
    [hive@lgh test]$ find . -type l  #查找链接文件
    ./d

    2.3.2、从文件大小判断

    -size N[bcwkMG] 

    b  #512字节的(默认单位)
    c  #1字节的
    w  #2字节
    k  #1024字节
    M  #1024k
    G  #1024M

    empty:空文件,对于目录来说,则是空目录

    [hive@lgh test]$ ll
    total 8
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 a
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:06 c
    lrwxrwxrwx 1 hive hive    1 Sep 30 10:08 d -> a
    [hive@lgh test]$ find -size 1  #文件大小为1字节
    ./d
    [hive@lgh test]$ find -size -2 #文件大小小于2字节
    ./c
    ./d

    2.3.3、从文件名后者路径名判断

    -name pattern   #文件的basename(不包括其前导目录的纯文件名)能被通配符模式的pattern匹配到。需要注意的是,在find中的通配元字符"*"、"?"和"[]"是能够匹配以点开头的文件的
    -iname pattern  #不区分大小的"-name"               
    -path pattern   #文件名能被通配符模式的pattern匹配到。此模式下,通配元字符"*"、"?"和"[]"不认为字符"/"或"."是特殊字符,也就是说这两个字符也在通配范围内,所以能匹配这两个字符。    
    -ipath pattern  #不区分大小写的"-path"                        
    -regex pattern  #文件名能被正则表达式pattern匹配到的文件。正则匹配会匹配整个路径,例如要匹配文件名为"./fubar3"
                    #的文件,可以使用".*bar."或".*b.*3",但不能是"f.*r3",默认find使用的正则类型是Emacs正则,但可以使用-regextype来改变正则类型                            
    -iregex pattern #不区分大小写的"-regex"
    [hive@lgh test]$ ll
    total 8
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:52 1.bak
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 1.txt
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:52 2.bak
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 2.txt
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:52 3.bak
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 3.txt
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 4.txt
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:52 a
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:06 c
    lrwxrwxrwx 1 hive hive    1 Sep 30 10:08 d -> a
    [hive@lgh test]$ find . -name "*.bak"
    ./3.bak
    ./1.bak
    ./2.bak
    [hive@lgh test]$ find . -path "./a/*.txt"
    ./a/1.txt
    ./a/2.txt
    ./a/3.txt
    [hive@lgh test]$ find . -regex ".*txt"    #正在匹配
    ./1.txt
    ./a/1.txt
    ./a/2.txt
    ./a/3.txt
    ./2.txt
    ./4.txt
    ./3.txt

    2.3.4、从文件权限判断

    -perm mode  #精确匹配给定权限的文件。"-perm g=w"将只匹配权限为0020的文件。当然,也可以写成三位数字的权限模式
    -perm /mode #匹配任意给定权限位的权限,例如"-perm /640"可以匹配出600,040,700,740等等,只要文件权限的任意位能
                #包含给定权限的任意一位就满足
    -executable #具有可执行权限的文件。它会考虑acl等的特殊权限,只要是可执行就满足。它会忽略掉-perm的测试
    -readable   #具有可读权限的文件。它会考虑acl等的特殊权限,只要是可读就满足。它会忽略掉-perm的测试
    -writable   #具有可写权限的文件。它会考虑acl等的特殊权限,只要是可写就满足。它会忽略掉-perm的测试(不是writeable)
    # find . -type f -perm 0777 -print
    # find / -type f ! -perm 777
    # find / -perm 2644
    # find / -perm /u=s

    2.3.5、从文件所属情况判断

    -gid n       #gid为n的文件
    -group gname #组名为gname的文件
    -uid n       #文件的所有者的uid为n
    -user uname  #文件的所有者为uname,也可以指定uid
    -nogroup     #匹配那些所属组为数字格式的gid,且此gid没有对应组名的文件
    -nouser      #匹配那些所有者为数字格式的uid,且此uid没有对应用户名的文件
    # find / -user root -name tecmint.txt
    # find /home -user tecmint
    # find /home -group developer
    # find /home -user tecmint -iname "*.txt"

    2.3.6、从文件的时间参数判断

    -anewer file:atime比mtime更接近现在的文件。也就是说,文件修改过之后被访问过
    -cnewer file:ctime比mtime更接近现在的文件
    -newer  file:比给定文件的mtime更接近现在的文件。
    -newer[acm]t TIME:atime/ctime/mtime比时间戳TIME更新的文件
    -amin  n:文件的atime在范围n分钟内被访问过,对这个文件运用 more、cat等命令。ls、stat命令都不会修改文件的访问时间。注意,n可以是(+ -)n,例如-amin +3表示在3分钟以前
    -cmin  n:文件的ctime在范围n分钟内被修改过文件的状态,通过chmod、chown命令修改一次文件属性,这个时间就会更新
    -mmin  n:文件的mtime在范围n分钟内被修改过内容,vim/vi修改保存
    -atime n:文件的atime在范围24*n小时内被访问过
    -ctime n:文件的ctime在范围24*n小时内被修改状态
    -mtime n:文件的mtime在范围24*n小时内被修改内容
    -used  n:最近一次ctime改变n天范围内,atime改变过的文件,即atime比ctime晚n天的文件,可以是(+ -)n
    # find / -mtime 50
    # find / -atime 50
    # find / -mtime +50 –mtime -100
    # find / -cmin -60
    # find / -mmin -60
    # find / -amin -60

    2.4、actions

        actions部分一般都是执行某些命令,或实现某些功能。这部分是find的command line部分,注意,action是可以写在tests表达式前面的,它并不一定是在test表达式之后执行。

    -delete         #删除文件,如果删除成功则返回true,如果删除失败,将给出错误信息。"-delete"动作隐含"-depth"-exec command;  #注意有个分号";"结尾,该action是用于执行给定的命令。如果命令的返回状态码为0则该action返回true。
                    #command后面的所有内容都被当作command的参数,直到分号";"为止,其中参数部分使用字符串"{}"时,它
                    #表示find找到的文件名,即在执行命令时,"{}"会被逐一替换为find到的文件名,"{}"可以出现在参数中的
                    #任何位置,只要出现,它都会被文件名替换。
                    #注意,分号";"需要转义,即";",如有需要,可以将"{}"用引号包围起来
    -ok command ;   #类似于-exec,但在执行命令前会交互式进行询问,如果不同意,则不执行命令并返回false,如果同意,则执
                    #行命令,但执行的命令是从/dev/null读取输入的
    -print          #总是返回true。这是默认的action,输出搜索到文件的全路径名,并尾随换行符"
    "。由于在使用"-print"时所有的结
                    #果都有换行符,如果直接将结果通过管道传递给管道右边的程序,应该要考虑到这一点:文件名中有空白字符(换行符、制表
                    #符、空格)将会被右边程序误分解,如文件"ab c.txt"将被认为是ab和c.txt两个文件,如不想被此分解影响,可考虑使
                    #用"-print0"替代"-print"将所有换行符替换为""
    -print0         #总是返回true。输出搜索到文件的全路径名,并尾随空字符""。由于尾随的是空字符,所以管道传递给右边的程序,然后
                    #只需对这个空字符进行识别分隔就能保证文件名不会因为其中的空白字符被误分解
    -prune          #不进入目录,所以可用于忽略目录,但不会忽略普通文件。没有给定-depth时,总是返回true,如果给定-depth,则直接
                    #返回false,所以-delete(隐含了-depth)是不能和-prune一起使用的
    -ls             #总是返回true。将找到的文件以"ls -dils"的格式打印出来,其中文件的size部分以KB为单位
    [hive@lgh test]$ ll
    total 8
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:52 1.bak
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 1.txt
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:52 2.bak
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 2.txt
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:52 3.bak
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 3.txt
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:51 4.txt
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:52 a
    drwxrwxr-x 2 hive hive 4096 Sep 30 10:06 b
    -rw-rw-r-- 1 hive hive    0 Sep 30 10:06 c
    lrwxrwxrwx 1 hive hive    1 Sep 30 10:08 d -> a
    [hive@lgh test]$ find . -type f -print -name "*.bak"  #这里有一个action -print,则会覆盖末尾默认的-print,所以在-type -f -print会把所有文件打印出来,
    #然后-name "*.bak"虽然匹配到了文件,但是没有了action,所以没有操作显示 .
    /3.bak ./1.txt ./a/1.txt ./a/2.txt ./a/3.txt ./1.bak ./2.txt ./4.txt ./2.bak ./3.txt ./c [hive@lgh test]$ find . -type f -print -name "*.bak" -ls #这个在上一种情况对 -name "*.bak"增加action -ls ,所以会把符合条件的ls出来 ./3.bak 64356992 0 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 ./3.bak ./1.txt ./a/1.txt ./a/2.txt ./a/3.txt ./1.bak 64356990 0 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 ./1.bak ./2.txt ./4.txt ./2.bak 64356991 0 -rw-rw-r-- 1 hive hive 0 Sep 30 10:52 ./2.bak ./3.txt ./c
    [hive@lgh test]$ find . -name "*.txt"
    ./1.txt
    ./a/1.txt
    ./a/2.txt
    ./a/3.txt
    ./2.txt
    ./3.txt
    [hive@lgh test]$ find . -path  "./a" -prune -o -name "*.txt"
    ./1.txt
    ./a   #被忽略的目录也在里面
    ./2.txt
    ./3.txt

    注意:如果find评估完所有表达式后发现没有action(-prune这个action除外),则在最末尾加上-print作为默认的action。注意,这个默认的action是在评估完所有表达式后加上的。且还需注意,如果只有-prune这个action,它还是会补上-print。

    常用命令:

    find /backup/rman_backup/ -mtime +45 -exec rm -rf {} ;  删除45天前的文件,这样的命令一般可以用来删除一些日志,或者一些临时文件

    find /tmp -mtime +7-size +1M -exec rm -rf {} ;

    find -mtime +7 -nameabc* -exec rm -rf {} ;

    find /tmp -mtime +7-size +1M -ok rm -rf {} ;

    更多linux文章请见:linux&shell学习系列

    参考:

    https://www.cnblogs.com/f-ck-need-u/p/6995529.html#auto_id_5

    https://www.cnblogs.com/machangwei-8/p/10352567.html

    https://blog.csdn.net/hetoto/article/details/84101745

  • 相关阅读:
    lrzsz踩坑记
    《西安游记》
    《这世界那么多人》
    Go 日常开发常备第三方库和工具
    Go 里的超时控制
    菜鸟轻松拿offer: 软件测试工程师面试秘笈
    Django 练习教程
    JasperReports入门教程(五):分组打印
    并发的特性和锁的原理,分类
    面试高频算法
  • 原文地址:https://www.cnblogs.com/zsql/p/11612006.html
Copyright © 2011-2022 走看看