Linux命令分析:find

来源:互联网 发布:软件更新 编辑:程序博客网 时间:2024/06/08 18:13

用途:在指定目录结构下查找特定文件

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

默认path为当前目录,默认expression为 -print

选项-H,-L和-P控制对符号链接的处理方式,必须位于path参数之前

find指令的执行原理是递归地遍历指定目录树,先执行五个real option选项(-P,-L,-H,-D,-Olevel)进行全局设置,然后对整个命令做语法检查,判断path及表达式的格式,表达式先根据operators进行结合,然后依次从左到右进行求值,对path中的每个文件依次执行表达式,由于要遍历目录甚至整个文件系统,故find命令执行较慢


参数:

-P   不跟踪符号链接(默认选项),只比对符号链接文件本身的属性

-L   跟踪符号链接,比对符号链接所指向的文件的属性(除非是broken symbolic link或find命令无法检查所指向的文件),该选项自带-noleaf参数,如果符号链接指向某个子目录,则find会搜索该子目录,-L选项与-lname和-ilname合用将报错

-H   不跟踪符号链接,除非是后面在命令行里指定文件是符号链接,在这种情况下,无论所链接的文件是什么都将以其属性比对,除非该符号链接是broken的,则以符号链接文件本身的属性比对,如果符号链接指向某个目录,则find会遍历该目录

注:如果-H,-L和-P中有多项被指定,则只有最后面的一项生效

-D   排错,在find无法找到期望的结果时有用,后接的参数用逗号隔开,这些参数在不同Linux发行版中不一定互通,以find -D help输出结果为准,以下为-D的参数:

help

tree   列出表达式目录树expression tree的初始形态和最终形态

stat   文件匹配过程中,当被stat或lstat系统调用检查时,将过程显示出来

opt   依据最优的表达式目录树显示diagnostic信息

rates   显示汇总信息,包括predicate判断式执行成功和失败的次数

-Olevel   开启查询优化,有0-3四个级别,对后面的查询参数进行排序,用于提高查询效率


表达式expression由选项options,判断式tests,动作actions组成,之间用逻辑运算符operators隔开,缺省operators是-and

当expression后面不接除了-prune,-print外的actions时,对所有返回值为true的文件有效


options针对的是本次查找操作而不是某个 文件,通常返回值为true,除了-daystart,-follow和-regextype这三个选项,因为options通常在find程序对命令行进行语法检查之前就已经执行了,而上述三个选项和后面命令行输入的判断式有关,故为清晰起见,规定这三个选项要写在expression开头,否则会warning

-d   等效于-depth,同时与FreeBSD,NetBSD,MacOS X和OpenBSD兼容

-daystart   从本日0点开始计算时间(包括-amin -atime -cmin -ctime -mmin -mtime)

-depth   先遍历目录下的内容,然后才检查目录文件本身

-follow   不跟踪符号链接,-L会使之失效,隐含-noleaf选项

-ignore_readdir_race   find命令在目录里读到某文件存在,在检查该文件信息之前如果该文件被删除,本选项将不会报错

-maxdepth levels   设置遍历目录的最大层级,即最多只遍历到目录下第levels层

-mindepth  levels   设置遍历目录的最小层级,即只遍历第levels层下面的目录,当前目录的子目录深度为1,子目录的子目录深度为2,-mindepth1意味着处理目录下所有文件

-mount   仅在当前文件系统执行,与-xdev等效,且可兼容其他版本的find

-noleaf   不为“目录中子目录数量为硬链接数-2”这种假设做搜索优化,这个选项在搜索不遵循UNIX文件系统链接约定的那些文件系统时有用,find查找文件实际上是stat每个目录文件的内容,对目录来说,只遍历到比其硬链接数少2个子目录后就不再向下检查了,这是因为对于一个典型的类UNIX系统来说,一个目录文件至少有两个硬链接,分别是/和./,另外如果其下还有子目录,则子目录还有个上级目录文件../,那就至少是三个硬链接了,所以find默认假设目录拥有其硬链接数-2个子目录,硬链接数为2的目录为directory tree的leaf,程序到此不再向下stat,极大的提高了搜索速度

-regextype type   如果不指定该选项,默认正则表达式语法是emacs,该选项可指定语法,目前支持posix-awk,posix-basic,posix-egrep和posix-extended

-xautofs   不在autofs挂载的文件系统执行

-xdev   不在当前文件系统外执行


tests判断式可将后面命令行里指定的文件与path中的文件进行比对,其中可含三种数字参数:

+n   比n大

-n   比n小

n   等于n

-amin n   文件在之前第n分钟时被access过(即atime在now-3min和now-2min之间),具体算法是(当前时间-atime)/ 1min,然后再取整数部分加1

-anewer file   文件的atime比文件的mtime要晚,前面有-L或-H选项时,比对symbolic link将使用被链接文件的atime

-atime n   对文件的最后访问是n天之前,算法是(当前时间-atime)/ 24hours,然后取整。故-atime +1代表文件2天前被访问过

-cmin n   对文件的mtime改变发生在之前第n分钟

-cnewer file   文件的ctime比mtime要晚,前面有-L或-H选项时,比对symbolic link将使用被链接文件的ctime

-ctime n   文件的ctime是在n天前,算法同-atime

-executable   用于匹配文件是否可执行或目录是否可搜索,与-perm判断的机制不同,只是调用access(2)这个system call,因此有可能被开启了UID mapping功能的服务器所误导,最后得到的文件不一定都可实际执行

-false   总是返回false值

-fstype type   文件在type类型的文件系统上,有效的文件系统类型在不同版本的UNIX上是不同的,一些版本上的不完全列表有:ufs,4.2,4.3,nfs,tmp,mfs,S51K,S52K,可用-printf %F指令来查找你的文件系统类型

-gid n   文件的数字形式的组ID为n(n为/etc/group里组所对应的数字)

-group gname   文件属于gname组(gname变量可用数字组id)

-ilname pattern   与-lname类似,但不区分大小写

-lname pattern   文件是符号链接,使用后接的pattern字符串来匹配,若该字符串中含有metacharacter(元字符,BASH中的特殊字符,由shell解释)"."或"/",只当其是普通字符,不作特殊解释,与-L或-follow合用时无效

-iname pattern   与-name类似,但不区分大小写

-inum n   文件的inode号为n,通常用来查看硬链接,可用-samefile代替

-iregex pattern   与-regex类似,但不区分大小写

-iwholename pattern   与-wholename类似,但不区分大小写

-links n   文件有n个硬链接

-mmin n   对文件的mtime改变发生在之前第n分钟

-mtime n   文件的mtime是在n天前,算法同-atime

-name pattern   用文件名(路径去除了前面的目录,比如/etc/passwd的文件名是passwd)去匹配后接的pattern字符串,元字符* ? [ ]可以通配文件名开头的".",使用-prune来略过某个目录及其下文件。该参数调用fnmatch(3)这个库函数来匹配文件,注意要给pattern字符串加上引号来确保shell不会对其中的特殊字符进行解释

-newer file   查找比参考file的mtime时间更晚的文件,与-L或-L参数合用时,file若是符号链接则采用其链接到文件的mtine

-newerXY reference   将文件的时间戳与变量reference进行比对,reference可以是文件名也可以是个表示时间的字符串,X和Y是两个占位符,可以从下列参数中选择填充,这些参数指定了用来比对的时间类型

a   使用atime比对

B   使用文件的创建时间比对

c   使用ctime比对

m   使用mtime比对

t   reference本身就是时间

以上的填充参数有些不可滥用,比如X位不可用t,参数B不是所有的发行版都支持

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

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

-path pattern   文件名与shell模式的pattern匹配,元字符"/","."不做特殊处理。例如,find . -path "./sr*sc"会找到./src/misc这个文件(如果存在的话)。如果要忽略一个完整的目录树,应使用-prune这样就不用检查目录树中的每个文件了,例如要跳过/src/emacs这个目录及其下所有文件,可以这样:find . -path ./src/emacs -prune -o print

注意,pattern变量用来匹配的是采用完整文件名的test,即在path指明的路径下遍历文件,匹配这些文件的绝对路径(目录名+文件名),比如下面这个命令就无法生效:find bar -path /foo/bar/myfile -print  因为bar不是有效的目录名,无法与-path后面的pattern组成完整文件名

-perm mode   文件的权限位等于mode变量(八进制数或符号),该命令要求文件权限严格等于mode,比如-perm g=w就只会匹配到权限为0020的文件(-----w----),通常我们更愿意用/mode或-mode参数,因为他们可以匹配到所有所属组有w权限的文件

-perm -mode   文件的权限位包含mode变量(比如文件权限为0777,mode为0711),mode可用符号,但必须形如u=   g=   o=   这样指定对特定对象的权限,例如-perm -u=7

-perm /mode   文件的权限位转换成八进制数里任一位中的1与mode中对应,比如某文件权限为644,转换城八进制数为110 100 100,这时候find . -perm /001是找不到该文件的,而find . -perm /400就能找到该文件。如果-perm /后面不接mode,等效于-perm -000(匹配到所有文件)

-readable   匹配可读属性的文件,同-executable一样,该参数也是通过access(2)系统调用执行

-regex pattern   匹配pattern这个正则表达式的文件,这里匹配的是whole path全称路径,即要搜索./fubar3这个文件,应该用'.*bar'或'.*b.*3'这样的表达式,而不能用'f.*r3'这样的,因为无法匹配到前面的./目录名。默认使用emacs正则表达式语法,也可通过-regextype指定其他语法

-samefile name   与name变量指定文件inode号相同的文件,-L启用时,可匹配符号链接

-size n[cwbkMG]   文件占用n个存储单元,默认单位是512B的block,可在n后面加后缀指定存储单元大小,可选后缀如下:

b   大小为512字节的block(默认)

c   1字节的单元

w   2字节的单元

k   1KB的单元(1024B)

M   1MB的单元(1048576B)

G   1GB的单元(1073741824B)

注:size中不计入间接块indirect block(inode所在block记录不完文件的blocks,在末尾加一个指针,指向另一个block继续记录),同时也不计入稀疏文件中未实际分配的block

-true   总是返回true

-type c   文件是c类型的,类型可选值如下:

b   特殊块文件(缓冲的)            #如/dev/sda   /dev/loop0等,find / -type b自行查看

c   特殊字符文件(不缓冲)        #如/dev/null等

d   目录文件

p   命名管道FIFO

f    普通文件

l    符号链接

s   套接字socket

D   门(Solaris特有)

-uid n    文件的数字形式的用户ID为n(n为/etc/passwd里组所对应的数字)

-used n   文件的最后一次access是在最后一次状态被修改(ctime)的n天以后

-user uname   文件的所有者是uname(可使用userID)

-writable   匹配可写属性的文件,同-executable一样,该参数也是通过access(2)系统调用执行

-xtype c   和-type相同,除非文件是个符号链接。对于一个符号链接,在-H或-P选项指定的情况下,如果指向的是一个变量c类型的文件,则返回true;在-L选项指定的情况下,如果变量c是“l”即符号链接,则返回true。换句话说,-xtype检查的是-type忽略的符号链接所指向文件

-context pattern   匹配安全上下文security context为parttern的文件


actions是针对某个具体文件进行的操作,如下:

-delete   删除匹配到的文件,删除成功后返回true,如果删除失败,会显示error message。该参数自带-depth选项,由于find命令行是按照表达式来解释的,如果把-delete放在expression开头有可能使find试图删除path起点下的所有文件,所以一定要确切指出遍历的深度。-delete和-prune参数不可合用

-exec command   执行-exec后面接的命令,返回值为0则为true。find命令的强大功能很大程度上来自于这个操作,可将前面find找到的文件调用外部命令进行处理。-exec后接的所有参数都将被视为command,直到出现;为止,所以这个命令后面一定要接分号,同时应该在;前加上转义符\以防止其被shell解释为特殊字符。-exec后接的命令会对find到的每个文件执行一次,所以用字符串{}代替当前正在处理的文件名,command中出现的所有{}都会被替换(有的版本find则不然,只替换某个单独参数下的{}),}与\;之间一定要有一个空格,所以该命令的一般形式是find . EXPR1 -exec command {} \;   命令是从起始目录开始执行的。-exec操作会带来一些不可避免的安全问题,可以用-execdir代替

-exec command {} +   类似-execdir command {} + 只是从起始目录开始执行

-execdir command {} +   与-exec command相比,主要解决两个问题:一是find命令在-exec下会将所有匹配到的文件一起传递给command执行,但有的系统对能传递给exec的命令长度有限制,这样find运行一段时间后会溢出,exec后面加+的作用是使每次find建立的command line只包含同一个子目录里的匹配文件,这时要确保PATH环境变量中不包含"."字符。另外一个对每一个匹配的文件,-exec后接的命令都会建立一个线程,一方面线程过多可能引发系统性能下降,另一方面线程共享内存和某些寄存器,因此不同线程在解析所匹配到的文件的path时,可能引发race conditions竞争条件,而-execdir每次只同时匹配同一子目录里的文件,其path相同,能避免race conditions。

其实更好的办法是使用xargs,xargs可以自行设定每次获得多少参数来执行,find命令配合xargs和exec几乎可以对匹配到的文件执行所有命令

-fls file   返回值为true;类似-ls但是像-fprint那样写入file

-fprint file   返回值为true;将文件全名打印到文件file中。如果find运行时file不存在,则会创建一个,如果存在,则会被覆盖。文件名/dev/stdout和/dev/stderr会作特殊处理,他们分别指的是标准输出和标准错误输出

-fprint0 file   返回值为true;类似-printf0但像-fprint那些写入file

-fprint file format   返回值为true;类似-printf但像fprint那样写入file

-ls   返回值为true;以ls -dils这样的格式列出当前文件并打印到标准输出。默认的block是1K大小,除非在环境变量POSIXLY_CORRECT中设置

-ok command   类似-exec但执行命令前先向用户询问(在标准输入),显然这样更安全

-okdir command   类似-execdir但执行命令前先询问用户

-print   返回值为true;在标准输出打印文件全名,然后接一个换行符。该参数主要用于将find的输出通过管道传递给其他程序时,某些文件名有可能含有换行符

-print0   返回值为true;打印文件全名到标准输出,后接一个null字符。这样可以使处理find的输出的程序可以正确解释带有换行符的文件名,该参数等效于xargs -0

-printf format   返回值为true;在标准输出打印format,会解释\ 转义和% 变量。字段宽度和精度可像C函数printf那样来指定。不同于-print,-printf不会在字符串后加换行符,可用的escapes和directives如下:

\a   警告铃声

\b   退格 Backspace

\c   立即停止以当前格式输出并刷新输出设备

\f   换页 Form feed

\n   换行 Newline

\r   回车 Carriage return

\t   水平制表符

\v   竖直制表符

\0   ASCII字符NUL

\\   输出一个\

\NNN   ASCII编码是八进制NNN的字符

\作为转义符,后接的任何字符都会被当作普通字符打印输出

%%   只输出一个%

%a   文件最后一次access时间,采用C函数ctime返回值的格式

%Ak   文件最后一次access时间,采用变量k指定的格式,可以是"@"或C函数strftime的指令格式,下面列出了k可用的值,部分不是所有系统可用,因为不同系统中strftime也不同

@   从Jan.1,1970,00:00 GMT起的秒数,带小数部分

时间字段

H   小时(00到23)

I    小时(01到12)

k    小时(0到23)

l    小时(1到12)

M   分钟(00到59)

p   locale中的AM或PM

r   12小时格式的时间   hh:mm:ss [AP]M

S   秒(00到61),带小数部分

T   24小时格式的时间   hh:mm:ss

*    日期和时间,中间用+隔开,形如   2004-04-28+22:22:05.0   秒所在字段带小数部分

X   locale中的时间表示法   H:M:S

Z   时区(如EDT),不指定时为空

日期字段

a   locale中的一星期中每天名称的缩写(Sun至Sat)

A   locale中的一星期中每天名称的全拼,可变长度(Sunday至Saturday)

b   locale中的每月名称的缩写(Jan到Dec)

B   locale中的每月名称的全拼,可变长度(January到December)

c   locale中时间和日期表示,形如   Sat Nov 04 12:02:33 EST 1989   该格式与ctime(3)函数相同,为保证两者的兼容性,此处秒字段无小数部分

d   每月当中的日子(01到31)

D   日期(mm/dd/yy)

h   与b相同

j    一年当中的日子(001到366)

m   月份(01到12)

U   以周日为每周起始,一年中的星期(00到53)

w   每星期中的日子(0到6)

W   以周一为每周起始,一年中的星期(00到53)

x   locle中的日期表示(mm/dd/yy)

y   年份的最后两位(00到99)

Y   年份(从1970开始)

%b   文件大小,以512B大小的block数为单位

%c   文件状态的最后一次修改时间,采用C函数ctime返回值的格式

%Ck   文件状态的最后一次修改时间,格式由变量k指定,类似%Ak

%d    文件在目录树中的深度,0代表文件是命令行参数

%D   文件所在的设备号(结构体的st_dev字段),十进制数

%f    去掉了前面目录的文件名

%F   文件所在的文件系统类型,该值可为-fstype所用

%g   文件的组名,或组ID号

%G   文件的组ID号

%h   文件名前面的目录部分

%i    文件的inode号

%k   文件大小,以1K block数为单位

%l    符号链接的目标(如果文件不是符号链接则为空字符串)

%m   文件的权限位(八进制)。

%M   文件的权限位(符号形式,形如ls列出的)

%n   文件的硬链接数

%p   文件名

%P   文件名,去掉了文件名中使之得以被找到的命令行参数

%s   文件大小,以字节为单位

%S   文件稀疏度   计算公式是   BLOCKSIZE*st_blocks / st_size

%t   文件内容的上一次修改时间,采用C函数mtime返回值的格式

%Tk   文件内容的最后一次修改时间,格式由变量k指定,类似%Ak

%u   文件的用户名,或用户ID

%U   文件的用户ID

%y   文件类型,形如ls -l所列出的,U代表未知类型

%Y   文件类型,类似%y,增加了以下symlinks:L为loop,N为nonexistent

%Z   文件的安全上下文(SELinux only)

在printf中%用来表示格式化输出,其本身将被省略,接在其后的所有字符都将被视为普通字符打印输出

-prune   位于要排除的目录后,没有给出-depth时返回值为true;不进入前面指定的目录,如果给出了-depth则返回false,由于-delete隐含了-depth,故不可与-prune合用

-quit   立即退出,未执行命令的文件将不再执行


operators   逻辑运算符,下面将按优先级从高到低排列:

(expr)   用括号将表达式括起来具有最高的优先级,由于shell中括号有特殊含义,一般会加转义符,形如 \(...\)  而不是 (...)

! expr   表达式的值为false则返回true

-not expr   与! expr相同,但不遵循POSIX规范

expr1 expr2   两个表达式之间隐含默认运算符and,若expr1为false则不执行expr2

expr1 -a expr2   同上

expr1 -and expr2   同上,但不遵循POSIX规范

expr1 -o expr2   逻辑运算符或,若expr1为真则expr2不会执行

expr1 -or expr2   同上,但不遵循POSIX规范

expr1,expr2   列表,expr1和expr2都会被执行,expr1的值被忽略,最后列出的是expr2的值



典型用法:

1.查找指定文件

在/根目录下查找文件名以ifcfg开头的文件,比如网卡配置文件

2.查找某类后缀的文件

在/var/log下查找.log后缀的文件,字符.代表当前目录


3.查找文件全名中包含某些字符的文件


如上,查找到与BASH变量有关的文件,双引号可以解释内含字符串中的变量符号$


4.查找特定路径下特定文件名的特定类型文件


-type判断式可查找特定类型文件,后接-ls操作对传递来的文件名列出详细信息,本例为和passwd有关的链接文件


5.查找文件时使用通配符




上面字符串表示查找文件名中第一个字符为数字,第二个字符为大写字母的文件;第二条命令中的?代表文件名中一定有第三个字符


6.在特定目录深度匹配文件


查找/etc下第一层有几个config目录


7.查找特定时间戳的文件


查找24小时内被修改过内容的普通文件(mtime),比如上面的日志文件
注:有的版本算法可能得到的是(n-1)*24 hours 至 n*24 hours 这段时间内被修改的文件,我的版本实测是得到小于n*24 hours内被修改的文件


有时候要的时间比较精确,不想计算是多少天或分钟前的时候,可以自行创建一个参考文件,指定其时间戳,然后通过-newer来判断


8.查找特定权限的文件


上为查找/var/log下权限为750的文件


查找/var/lib目录下other用户至少有执行权限的文件,-perm -mode可匹配大于或等于其的权限


9.查找特定大小的文件


上为找一个大于100M的文件,如果要找小于100M的则为-size -100M


10.查找属于特定用户或组的文件


查找指定用户root的邮件


11.搜索时忽略个别目录


通常格式是find PATH -path 要忽略的目录 -prune test action


12.将搜索结果打印到标准输出


查找根目录下ntp用户所有的文件并打印出权限


13.调用外部命令


将/var/log下的.log文件复制到/tmp目录,上面命令中-exex后全部视为command,对前面的每个文件执行一次,{}代表当前正在执行的文件,\;代表command结束


统计/usr/bin下脚本文件的个数,使用管道和xargs命令配合更灵活,find找到的文件作为参数一个个传递给xargs执行


14.使用逻辑连接符进行复杂查找(! -a -o)



如上,括号内的表达式具有最高优先级,同时括号前要加转义符,上为找到/目录下除/var和/tmp目录里的所有.log文件


 
原创粉丝点击