美文网首页LinuxLinux学习之路
Linux命令学习手册-find

Linux命令学习手册-find

作者: QuietHeart | 来源:发表于2019-12-24 09:37 被阅读0次

    find pathname -options [-print -exec -ok ...]

    功能

    find 用于查找符合某些特性的文件。由于 find 具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时间来了解一下。

    即使系统中含有网络文件系统( NFS), find 命令在该文件系统中同样有效,只要你具有相应的权限。

    描述

    find 命令的参数

    find 的所有参数均为可选

    • pathname : find 命令所查找的目录路径。例如用.来表示当前目录,用 / 来表示系统根目录。

    • -printfind 命令将匹配的文件输出到标准输出。

    • -execfind 命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为 command { } \; ,注意 { }\; 之间的空格。

    • -ok : 和 -exec 的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。

    find 命令选项

    • -name 按照文件名查找文件。

    • -perm 按照文件权限来查找文件。

    • -prune 使用这一选项可以使 find 命令不在当前指定的目录中查找,如果同时使用 -depth 选项,那么 -prune 将被 find 命令忽略。

    • -user 按照文件属主来查找文件。

    • -group 按照文件所属的组来查找文件。

    • -mtime -n +n

      按文件更改时间来查找文件, -n 表示文件更改时间距现在 n 天以内, +n 表示文件更改时间距现在 n 天以前。 find 命令还有 -atime-ctime 选项,但它们都和 -m time 选项。

    • -nogroup 查找无有效所属组的文件,即该文件所属的组在 /etc/groups 中不存在。

    • -nouser 查找无有效属主的文件,即该文件的属主在 /etc/passwd 中不存在。

    • -newer file1 ! file2 查找更改时间比文件 file1 新但比文件 file2 旧的文件。

    • -type

      查找某一类型的文件,诸如:

      • b 块设备文件。

      • d 目录。

      • c 字符设备文件。

      • p 管道文件。

      • l 符号链接文件。

      • f 普通文件。

    • -size n [cwbkMG] : 查找文件长度为 n 块的文件,带有 c 等时表示文件长度(如 c 表示字节计)。

    • -depth :在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。

    • -fstype :查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件 /etc/fstab 中找到,该配置文件中包含了本系统中有关文件系统的信息。

    • -mount :在查找文件时不跨越文件系统 mount 点。

    • -follow :如果 find 命令遇到符号链接文件,就跟踪至链接所指向的文件。

    • -cpio :对匹配的文件使用 cpio 命令,将这些文件备份到磁带设备中。

    另外,下面三个的区别:

    • -amin n 查找系统中最后N分钟访问的文件

    • -atime n 查找系统中最后n*24小时访问的文件

    • -cmin n 查找系统中最后N分钟被改变文件状态的文件

    • -ctime n 查找系统中最后 n*24 小时被改变文件状态的文件

    • -mmin n 查找系统中最后N分钟被改变文件数据的文件

    • -mtime n 查找系统中最后 n*24 小时被改变文件数据的文件

    使用 execok 来执行shell命令

    使用 find 时,只要把想要的操作写在一个文件里,就可以用 exec 来配合 find 查找,很方便的。

    在有些操作系统中只允许 -exec 选项执行诸如 lsls -l 这样的命令。大多数用户使用这一选项是为了查找旧文件并删除它们。建议在真正执行 rm 命令删除文件之前,最好先用 ls 命令看一下,确认它们是所要删除的文件。

    exec 选项后面跟随着所要执行的命令或脚本,然后是一对儿 { } ,一个空格和一个 \ ,最后是一个分号。为了使用 exec 选项,必须要同时使用 print 选项。如果验证一下 find 命令,会发现该命令只输出从当前路径起的相对路径及文件名。

    举例

    按名称

    在当前目录中查找任何扩展名为 .c 的文件:

    $find ./ -name '*.c'
    

    $find ./ -name \*.c
    

    $find -name '*.c'
    

    输入之后,输出如下:

    ./hello.c
    ./1/main.c
    ./1/hello.c
    ./hello2.c
    

    这里,当前目录只用 . 也行,如果不用转义, *.c 必须括在引号(单/双)当中,如果不指定路径,将在当前目录找; 默认把子目录下的也都找出来了。

    ./test./viStudy 目录查找所有 .c 文件:

    $find test viStudy/ -name '*.c'
    

    输入之后,输出如下:

    test/test_out_direct.c
    viStudy/hello.c
    viStudy/1/main.c
    viStudy/1/hello.c
    viStudy/hello2.c
    

    这里,如果您没有相应的权限,您在开始浏览许多目录时将生成错误消息例如如下的提示:

    find:  /tmp/orbit-root: Permission denied
    

    可以不让错误输出,防止混乱:

    $find /usr /home  /tmp -name "*.jar" 2>/dev/null
    

    不区分大小写的 find 查找:

    $find downloads -iname '*.gif'
    

    输入之后,输出如下:

    downloads/.xvpics/Calendar05_enlarged.gif
    downloads/lcmgcfexsmall.GIF
    

    这里,默认情况下, find 是区分大小写的。对于不区分大小写的 find ,将 -iname 测试替换为 -name

    列出当前目录和所有子目录中的所有文件(包括隐藏文件)的完整清单:

    $find
    

    $find .
    

    $find . -print
    

    输入之后,输出如下:

    .
    ./any
    ./tags
    ./hello.c
    ./1
    ./1/main.c
    ...省略...
    

    按类型

    查找某(当前)目录中的所有子目录:

    $find . -type d
    

    $find -type d
    

    输入之后,输出如下:

    .
    ./1
    

    查找某(当前)目录中的所有符号链接:

    $find . -type l
    

    输入之后输出如下:

    ./hello2s
    

    这里, ./hello2s 是一个软链接,这个命令显示的也是软链接。其他 find 可以找到的文件类型包括:

    • b — 块(缓存)特殊
    • c — 字符(未缓存)特殊
    • p — 命名管道 (FIFO)
    • s — 套接字

    ls 列出软链接需要用 -ls ,用管道不行。如下:

    $find . type l -ls
    

    输出:

    56231215    0 lrwxrwxrwx   1 quietheart member          6 May 16 16:14 ./hello2s -> hello2
    

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

    $ find . -name "*.XC" -mount -print
    

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

    告知 find 在指定文件系统(例如 vfat )中查找:

    $find / -name  "*.txt" -fstype vfat
    

    还有

    $find / -name  "*.txt" -mount 2
    

    等等,不常用就不多说了。

    按时间

    查找在最近 1 *24小时内修改的所有文件:

    $find . -mtime -1
    

    输入之后输出如下:

    ./plsql/FORALLSample
    ./plsql/RegExpDNASample
    /plsql/RegExpSample
    

    查找恰好在 1 *24小时以前修改的所有文件:

    $find . -mtime 1
    

    查找 1 *24个多小时以前修改的所有文件:

    $find . -mtime +1
    

    这里, find 根据系统的时间戳搜索文件的选项。这些时间戳包括:

    • mtime — 文件内容上次修改时间

    • atime — 文件被读取或访问的时间

    • ctime — 文件状态变化时间

    这里, ctime 则需要更多的解释。由于 inode 维护着每个文件上的元数据,因此,如果与文件有关的元数据发生变化,则 inode 数据也将变化。这可能是由一系列操作引起的,包括创建到文件的符号链接、更改文件权限或移动了文件等。由于在这些情况下,文件内容不会被读取或修改,因此 mtimeatime 不会改变,但 ctime 将发生变化。

    这些时间选项都需要与一个值 n 结合使用,指定为 -nn+n:

    • -n 返回项小于 n
    • +n 返回项大于 n
    • n 返回项正好与 n 相等

    查找在不到 1 分钟以前读取的所有文件:

    $find . -amin -1
    

    输入之后,输出如下:

    ./.bashrc
    /.bash_history
    ./.xauthj5FCx1
    

    这里是刚刚登陆系统就运行了这个命令,所以输出这样。默认情况下, -mtime-atime-ctime 指的是最近 24 小时。但是,如果它们前面加上了开始时间选项,则 24 小时的周期将从当日的开始时间算起。您还可以使用 mminamincmin 查找在不到 1 小时的时间内变化了的时间戳。

    另外,应该注意的是,使用 find 命令查找文件本身将更改该文件的访问时间作为其元数据的一部分。

    查找在当前目录中 hello2.c 文件之后被编辑过的所有文件:

    $find . -newer hello2.c
    

    输入之后输出如下:

    .
    ./hello2s
    ./hello2h
    ./hello2
    

    这里,需要注意硬链接的特殊性(我不说,只有你明白了才知道我说的意思)。使用 -newer-anewer-cnewer 选项与特定的文件比较查找已修改或访问过的文件。这类似于 -mtime-atime-ctime

    • -newer 指内容最近被修改的文件
    • -anewer 指最近被读取过的文件
    • -cnewer 指状态最近发生变化的文件

    查找更改时间比文件httpd1.conf新但比文件temp旧的文件:

    $find -newer httpd1.conf  ! -newer temp -ls
    

    其中, 是逻辑非符号。

    按大小

    查找所有大于 5MB 的用户文件:

    $find / -size  +5000000c 2> /dev/null
    

    输入之后,输出如下:

    /var/log/lastlog
    /var/log/cups/access_log.4
    /var/spool/mail/bluher
    

    这里,把错误的信息定位到 /dev/null 了。

    结尾的 c 以字节为单位报告我们的结果。默认情况下, find 以 512 字节块的数量报告大小。如果我们将 c 替换为 k ,我们还会看到以千字节的数量报告的结果,如果使用 w ,则会看到以两字节字的数量报告的结果。

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

    $ find . -size +10 -print
    

    搜索所有零字节文件并将它们移至 /tmp/zerobyte 文件夹:

    $find test -type f  -size 0 -exec mv {} /tmp/zerobyte \;
    

    这里, -exec 操作允许 find 在它遇到的文件上执行任何 shell 命令。在本文的后面部分,您将看到其用法的更多示例。大括号允许移动每个空文件。

    查找test目录下的空文件:

    $find test -empty
    

    输入之后输出如下:

    test/foo
    test/test
    

    查找空文件用的是 -empty 选项。

    按权限、所属

    在当前目录下查找文件权限位为 755 的文件:

    $find . -perm 755 -print
    

    还有一种表达方法:在八进制数字前面要加一个横杠 - ,表示都匹配,如 -007 就相当于 777-006 相当于 666 .

    查找属于 user1name 或着属于 user2name 的文件:

    $find / -user user1name -or -user user2name
    

    查找既属于 user1name 又属于 user2name 用户的文件:

    $find / -user user1name -and -user2name
    

    查找在系统中属于非用户( ? )的文件:

    $find /-nouser
    

    查找在系统中属于 username 的文件:

    $find / -user username
    

    查找在系统中属于 groupname 的文件:

    $find / -group groupname
    

    按指定目录

    希望在 /apps 目录下查找文件,但不希望在 /apps/bin 目录下查找:

    $find /apps -path "/apps/bin" -prune -o -print
    

    在使用 -prune 选项时要当心,因为如果你同时使用了 -depth 选项,那么 -prune 选项就会被 find 命令忽略。

    /usr/sam 目录下查找不在 dir1 子目录之内的所有文件:

    $find /usr/sam -path "/usr/sam/dir1" -prune -o -print
    

    这里, find [-path ..] [expression] 在路径列表的后面的是表达式。

    -path "/usr/sam" -prune -o -print-path "/usr/sam" -a -prune -o -print 的简写表达式按顺序求值, -a-o 都是短路求值,与 shell 的 &&|| 类似。

    如果 -path "/usr/sam"= 为真,则求值 =-prune , -prune 返回真,与逻辑表达式为真;否则不求值 -prune ,与逻辑表达式为假。

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

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

    if -path "/usr/sam"  then
              -prune
    else
              -print
    

    避开多个文件夹:

    $find /usr/sam \( -path /usr/sam/dir1 -o -path /usr/sam/file1 \) -prune -o -print
    

    这里,圆括号表示表达式的结合。 \ 表示引用,即指示 shell 不对后面的字符作特殊解释,而留给 find 命令去解释其意义。

    确保先在一个目录中进行查找,然后才在其子目录中进行查找:

    $find -name "*test*" -depth
    

    输入之后,输出:

    ./test/test
    ./test
    ./localbin/test
    ./localbin/test_shell_var
    ./localbin/test.txt
    ./test2/test/test
    ./test2/test
    ./test2
    

    find 在至少下至目录树三个级别的目录中查找:

    $find / -mindepth 3  -name "*log"
    

    在目录树的前三个级别中查找日志文件:

    $find / -maxdepth 3  -name "*log"
    

    查找并执行命令:

    用 =ls -l=命令列出所匹配到的文件:

    $find . -type f -exec ls -l {  } \;
    

    输入之后,输出:

    -rw-r--r--    1 root     root        34928 2003-02-25  ./conf/httpd.conf
    -rw-r--r--    1 root     root        12959 2003-02-25  ./conf/magic
    -rw-r--r--    1 root     root          180 2003-02-25  ./conf.d/README
    

    这里, exec 选项后面跟随着所要执行的命令或脚本,然后是一对儿 {} ,一个空格和一个 \ ,最后是一个分号,注意 {} 内可以没有空格,但是 {} 后面、 \ 前面要有一个空格。

    /logs 目录中查找更改时间在5日以前的文件并删除它们:

    $find logs -type f -mtime +5 -exec rm {  } \;
    

    在shell中用任何方式删除文件之前,应当先查看相应的文件,一定要小心!当使用诸如 mvrm 命令时,可以使用 -exec 选项的安全模式。

    当前目录中查找所有文件名以 .LOG 结尾、更改时间在5日以上的文件并删除,删除之前先给提示:

    $find . -name "*.conf"  -mtime +5 -ok rm {  } \;
    

    输入之后,输出如下提示:

    < rm ... ./conf/httpd.conf > ? n
    

    这里,按 y 键删除文件,按 n 键不删除。

    匹配所有文件名为 passwd* 的文件,然后执行 grep 命令看这些文件中是否存在 sam 用户:

    $find /etc -name "passwd*" -exec grep "sam" {  } \;
    

    输入之后,输出:

    sam:x:501:501::/usr/sam:/bin/bash
    

    当前目录中文件属主具有读、写权限,并且文件所属组的用户和其他用户具有读权限的文件:

    $find . -type f -perm 644 -exec ls -l {  } \;
    

    查找 /var/logs 目录中更改时间在7日以前的普通文件,并在删除之前询问它们:

    $find /var/logs -type f -mtime +7 -ok rm {  } \;
    

    查找系统中所有属于 root 组的文件:

    $find . -group root -exec ls -l {  } \;
    

    输入之后,输出:

    -rw-r--r--    1 root     root          595 10月 31 01:09 ./fie1
    

    这里实际不用 -exec 也行,即: $find . -group root 。不过为了更详细列出相关的信息,使用 exec 选项对每个文件执行了 ls

    查找并删除访问时间在7日以来、含有数字后缀的 admin.log 文件:

    $find . -name "admin.log[0-9][0-9][0-9]" -atime -7  -ok rm {  } \;
    

    输入之后,输出:

    < rm ... ./admin.log001 > ? n
    < rm ... ./admin.log002 > ? n
    < rm ... ./admin.log042 > ? n
    < rm ... ./admin.log942 > ? n
    

    这里,只寻找了3位数的数字。

    高效的查找执行:

    使用 find 命令的 -exec 选项处理匹配到的文件时, find 命令将所有匹配到的文件一起传递给 exec 执行。但有些系统对能够传递给 exec 的命令长度有限制,这样在 find 命令运行几分钟之后,就会出现溢出错误;还可能导致有些系统进程过多,系统性能下降的问题,因而效率不高.

    使用 xargs 命令则只有一个进程。另外,在使用 xargs 命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。

    下面是 xargs 命令同 find 命令一起使用的一些例子:

    查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件:

    $find . -type f -print | xargs file
    

    输入之后,输出:

    ./.kde/Autostart/Autorun.desktop: UTF-8 Unicode English text
    ./.kde/Autostart/.directory:      ISO-8859 text\
    ...省略...
    

    当前目录下查找 file 开头的文件然后把结果保存到 /tmp/core.log 文件中:

    $find . -name "file*" -print | xargs echo "" > /temp/core.log
    

    在当前目录下查找所有用户具有读、写和执行权限的文件,并收回相应的写权限:

    $find . -perm -7 -print | xargs chmod o-w
    

    grep 命令在当前目录下的所有的普通文件中搜索 hostname 这个词:

    $find . -type f -print | xargs grep "hostname"
    

    $find . -name \* -type f -print | xargs grep "hostname"
    

    输入之后,输出:

    ./httpd1.conf:#     different IP addresses or hostnames and have them handled by the
    ./httpd1.conf:# VirtualHost: If you want to maintain multiple domains/hostnames on your
    

    注意,这里, \ 用来取消 find 命令中的 * 在shell中的特殊含义。

    其它

    相关文章

      网友评论

        本文标题:Linux命令学习手册-find

        本文链接:https://www.haomeiwen.com/subject/cjiogctx.html