find pathname -options [-print -exec -ok ...]
功能
find
用于查找符合某些特性的文件。由于 find
具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时间来了解一下。
即使系统中含有网络文件系统( NFS), find
命令在该文件系统中同样有效,只要你具有相应的权限。
描述
find
命令的参数
find
的所有参数均为可选
pathname
:find
命令所查找的目录路径。例如用.来表示当前目录,用/
来表示系统根目录。-print
:find
命令将匹配的文件输出到标准输出。-exec
:find
命令对匹配的文件执行该参数所给出的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
小时被改变文件数据的文件
使用 exec
或 ok
来执行shell命令
使用 find
时,只要把想要的操作写在一个文件里,就可以用 exec
来配合 find
查找,很方便的。
在有些操作系统中只允许 -exec
选项执行诸如 ls
或 ls -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 数据也将变化。这可能是由一系列操作引起的,包括创建到文件的符号链接、更改文件权限或移动了文件等。由于在这些情况下,文件内容不会被读取或修改,因此 mtime
和 atime
不会改变,但 ctime
将发生变化。
这些时间选项都需要与一个值 n
结合使用,指定为 -n
、 n
或 +n
:
-
-n
返回项小于n
-
+n
返回项大于n
-
n
返回项正好与n
相等
查找在不到 1 分钟以前读取的所有文件:
$find . -amin -1
输入之后,输出如下:
./.bashrc
/.bash_history
./.xauthj5FCx1
这里是刚刚登陆系统就运行了这个命令,所以输出这样。默认情况下, -mtime
、 -atime
和 -ctime
指的是最近 24 小时。但是,如果它们前面加上了开始时间选项,则 24 小时的周期将从当日的开始时间算起。您还可以使用 mmin
、 amin
和 cmin
查找在不到 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中用任何方式删除文件之前,应当先查看相应的文件,一定要小心!当使用诸如 mv
或 rm
命令时,可以使用 -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中的特殊含义。