- 浏览: 166168 次
- 性别:
- 来自: 南宁
最新评论
-
pipal:
jy1245626 写道引用Eclipse的代理这个是哪个功能 ...
eclipse启动tomcat成功,但却一直处在starting状态 -
jy1245626:
引用Eclipse的代理这个是哪个功能?,我eclips跑Jb ...
eclipse启动tomcat成功,但却一直处在starting状态 -
iany:
I have the same case before, it ...
eclipse启动tomcat成功,但却一直处在starting状态 -
pipal:
烟雨遥_sun 写道很强大,正好遇到这个问题,感谢楼主分享! ...
linux mysql mysql_real_connect函数导致内存泄露 -
烟雨遥_sun:
很强大,正好遇到这个问题,感谢楼主分享!
linux mysql mysql_real_connect函数导致内存泄露
转载一篇好文章:http://blog.csdn.net/jakee304/archive/2007/09/20/1792830.aspx
find之强大毋庸置疑,此处只是带领大家一窥find门径,更详细的说明见man find和 info find。
整篇文章循序渐进,从最常用的文件名测试项开始步步深入,到第六节基本讲完find处理文件的规则,再之后的章节是一些常用表达式的说明。
(此篇中所有选项及例子基于GNU find version 4.2.28)
(一)Get Start
最简单的find用法莫过于如此:
$ find .
查找当前目录下的所有文件。
find命令的一般格式为:
find [-H] [-L] [-P] [path...] [expression]
其中,'-H' '-L' '-P'三个选项主要是用来处理符号连接,'-H'表示只跟随命令行中指定的符号连接,'-L'表示跟随所有的符号连接,'-P'是默认的选项,表示不跟随符号连接。
例如,在我的当前目录下有一个符号连接e1000,现在我想查找文件名中最后一个字母是数字的源文件,那么
$ find -H . -name "*[0-9].c" -print
./2234.c
像上面这样写只能查找出当前目录下符合要求的文件,却找不出e1000下的文件。因此可以这么写:
$ find -H e1000 . -name "*[0-9].c" -print
或者使用 '-L'选项
$ find -L . -name "*[0-9].c" -print
格式中的[path...]部分表示以此目录为根目录进行搜索。
格式中的[expression]是一个表达式。最基本的表达式分为三类:设置项(option)、测试项(test)、动作项(action),这三类又可以通过逻辑运算符(operator)组合在一起形成更大更复杂的表达式。设置项(如-depth,-maxdepth等)针对这次查找任务,而不是仅仅针对某一个文件,设置项总是返回true;测试项(test)则不同,它针对具体的一个文件进行匹配测试,如-name,-num,-user等,返回true或者false;动作项(action)则是对某一个文件进行某种动作(最常见的如-print),返回true或者false。
正是[expression]部分的丰富,才使得find如此强大。此部分较复杂,后面慢慢说明。
(二)文件名
根据文件名来查找一个文件是大家经常遇到的事情,第一节中的'-name'正是解决此问题的。
-name属于表达式中的测试项(test),它按照文件名模式来匹配文件,若匹配则返回true,否则返回false。最好用引号将文件名模式引起来,防止shell自己解析要匹配的字符串。(可以用单引号也可以用双引号,单引号和双引号在shell环境中的区别见后续部分)
例如,想要的当前目录及子目录中查找文件名以一个大写字母开头或者以小写a或b开头的文件,可以用:
$ find . -name "[A-Za-b]*" -print
./a_book_of_c.chm
./TMP1234
如果想在当前目录查找文件名不以大写字母开头,之后跟一个小写字母,再之后是两个数字,最后是.txt的文件,可以这么用:
$ find . -name "[^A-Z][a-z][0-9][0-9].txt" -print
./@y38.txt
注意:此处的模式匹配并不符合正则表达式。
-name对大小写字母敏感,如果想匹配时不考虑大小写可以使用-iname测试项。'i'可以加在许多选项前面,比如-ipath,-iregex,-iwholename等等,都是表示大小写不敏感。
(三)正则表达式
使用上面的-name测试项能解决许多问题,但是有些还是不太好办,比如:查找当前目录下名称全部为数字的c源代码文件,这时就该'-regex'出手了。正则表达式绝对值得你去好好研究一下,在unix系统下太有用了,这里不做过多说明,请读者自行学习。
-regex 同样属于测试项。使用-regex时有一点要注意:-regex不是匹配文件名,而是匹配完整的文件名(包括路径)。例如,当前目录下有一个文件"abar9",如果你用"ab.*9"来匹配,将查找不到任何结果,正确的方法是使用".*ab.*9"或者".*/ab.*9"来匹配。
针对上面的那个查找c代码的问题,可以这么写:
$ find . -regex ".*/[0-9]*\.c" -print
./2234.c
还有一个设置项(option)'-regextype',可以让你根据自己的喜好选择使用的正则表达式类型,大家可以试试。
(四)wholename与path
既然上一节提到了完整文件名(包括路径名),那么这里不妨说一下-wholename和-path。
-wholename和-path都属于测试项(test),而且功能也一样。-path从字面上看给人一种错觉,好像只匹配路径名(或者目录名),其实它也可以匹配文件名,因此-wholename这个名字更贴切一些。
看看这个例子,当前目录下有一个phone目录,phone目录里有一个文件名称是puk.txt,使用-path:
$ find . -path '*phone/pu*'
./phone/puk.txt
另外要提一点:使用-path的一般格式是:find [path ...] -path pattern ...
它的意思是:在[path ...]部分指明的路径上,使用pattern匹配所有文件的完整文件名;而不是说在类似的pattern目录下查找文件。
(五)逻辑运算符
有了上面三个选项,你现在应该对文件名的相关匹配得心应手了,对于不是很复杂的查找应该也胜任了。但是看看这个例子,解释一下它在做什么?
$ find . -size +0c -wholename "*e*[0-9]*" -o ! \( -name "." -o -name "*phone" \) -prune -name "*.c" -user xixi -o -name "*phone"
下面是当前目录下的所有文件:
$ ls -l
total 224
-rw-r--r-- 1 xixi admin 0 2007-11-01 17:34 0dfe.c
-rw-r--r-- 1 abc admin 0 2007-10-30 15:56 0s8a.txt
-rw-r--r-- 1 abc admin 0 2007-11-04 01:00 0TMP123
-rw-r--r-- 1 abc admin 73 2007-11-05 15:33 2234.c
-rw-r--r-- 1 abc admin 72 2007-11-05 15:34 3e10.c
-rw------- 1 abc admin 224017 2006-03-16 12:16 a_book_of_c.chm
lrwxrwxrwx 1 abc admin 15 2007-11-04 11:48 e1000 -> ../e1000-7.6.9/
-rw-r--r-- 1 abc admin 70 2007-11-05 14:57 e100.dat
lrwxrwxrwx 1 abc admin 13 2007-11-05 14:59 e100puk.txt -> phone/puk.txt
-rw-r--r-- 1 abc admin 0 2007-11-06 22:21 e680phone
drwxr-xr-x 2 abc admin 37 2007-11-06 22:24 phone
drwxr-xr-x 2 abc admin 20 2007-11-07 01:07 phone1
drwxr-xr-x 2 abc admin 6 2007-11-05 15:37 phone2
-rw-r--r-- 1 abc admin 67 2007-11-04 12:23 @y38.txt
phone$ ls -l
total 4
-rw-r--r-- 1 abc admin 0 2007-11-06 22:24 e680gphone
-rw------- 1 abc admin 38 2007-11-05 14:58 puk.txt
phone1$ ls -l
total 0
-rw-r--r-- 1 xixi admin 0 2007-11-07 01:07 hello.c
phone2$ ls -l
total 0
要想解决上面的问题就得学习一下find中的逻辑运算符。逻辑运算符主要有以下几个,按照优先级从高到低的顺序如下:
( expr )
括号优先级最高,首先对括号内的求值
! expr
对expr表达式的值取反
-not expr
同上,但是POSIX不支持
expr1 expr2
不加任何运算符,相当于两个之间加and,即与运算,两个表达式值都为true整个才返回true。先对expr1表达式求值,若为false,则不对expr2求值。
expr1 -a expr2
同上
expr1 -and expr2
同上,但是POSIX不支持
expr1 -o expr2
表示对expr1和expr2两个表达式的值求或,左右两个值只要有一个为ture,整个表达式就是true。先对expr1表达式求值,若为ture,则不对expr2求值。
expr1 -or expr2
同上,但是POSIX不支持
expr1 , expr2
逗号表达式。expr1和expr2都会求值,但是只返回expr2的值,expr1的值会被丢弃
正是因为有一个求值的顺序,所以你才有可能见到这样的写法:
$ find . -name "*.txt" -o -print
表示,如果表达式-name "*.txt"为真,就不再执行另一个表达式-print,即查找所有不是以.txt结尾的文件。
再有,要查找当前目录下,文件名中包括字母'e',在'e'之后又有数字的不是目录文件的所有文件,可以这么写:
$ find . -name "*e*[0-9]*" ! -type d -print
./e1000
./e100.dat
./e100puk.txt
./3e10.c
大家可以自己多举几个例子试一下。
(六)-prune
-prune是一个动作项,它表示当文件是一个目录文件时,不进入此目录进行搜索。
要理解-prune动作,首先得理解find命令的搜索规则(也可以说find命令的算法)。
find命令递归遍历所指定的目录树,针对每个文件依次执行find命令中的表达式,表达式首先根据逻辑运算符进行结合,然后依次从左至右对表达式求值。以下面代码为例,进行说明
find PATHP1 OPT1 TEST1 ACT1 ( TEST2 or TEST3 ) ACT2
(1) 根据OPT1设置项进行find命令的整体设置,若没有-depth设置项,依次进行下面的步骤
(2) 令文件变量File = PATHP1
(3) 对File文件进行TEST1测试,若执行结果为false,转(8)
(4) 对File文件进行ACT1动作,若执行结果为false,转(8)
(5) 对File文件进行TEST2测试,若执行结果为true,转(7)
(6) 对File文件进行TEST3测试,若执行结果为false,转(8)
(7) 对File文件进行ACT2动作
(8) 若File文件是一个目录,并且没有被执行过-prune动作,则进入此目录
(9) 当前目录下是否还有文件,若有依次取一个文件,令File指向此文件,转(3);
(10) 判断当前目录是否是PATHP1,若是则程序退出;若不是,则返回上一层目录,转(9)
理解了上面的流程,那么不难理解下面的代码为什么只输出一个'.'
$ find . -prune
.
再有,当前目录下大于4090字节的文件有两个,而大于4096字节的文件只有一个,如下:
$ find . -size +4090c -print
.
./a_book_of_c.chm
$ find . -size +4096c -print
./a_book_of_c.chm
那么,将上面两个-print都替换为-prune,这两条命令分别输出什么?
$ find . -size +4090c -prune
.
$ find . -size +4096c -prune
./a_book_of_c.chm
这就是答案,如果你答对了,恭喜你,你已经掌握了find命令!
-prune经常和-path或-wholename一起使用,以避开某个目录,常见的形式是:
$ find PATH (-path <don't want this path #1> -o -path <don't want this path #2>) -prune -o -path <global expression for what I do want>
注意:如果同时使用-depth设置项,那么-prune将被find命令忽略。man手册页中这么说:"If -depth is given, false; no effect."
说到这里,又得说说-depth设置项。网上好多资料说-depth设置项的功能是“在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找”,这明显是错误的,man手册页中如是说:"-depth Process each directory's contents before the directory itself."。这有点像树的后序遍历,先遍历当前节点的所有子节点,然后再访问当前节点...
考考你:
下面的命令输出什么?为什么?
$ find . -depth -prune -name "*.c" -print
(七)时间戳
理解了上面几节,你已经掌握了find命令的“道” ^_^ ,下面这几节只是介绍一些常用、好用的“招式”。这一节介绍时间戳。
文件有三个时间属性:创建时间、最近修改时间、最近访问时间。
最近修改时间又包括两种,一是文件的状态(也即权限如rwx等)最近被修改时间,一是文件的数据(也即内容)最近被修改时间。touch命令改变的即是文件数据最近被修改时间。
最近访问时间,指的是最近一次文件数据(内容)被访问的时间。因此,使用ls命令输出文件的相关信息并不会修改文件的最近访问时间。
find命令提供了针对文件的最近访问时间、文件状态最近被修改时间、文件数据最近被修改时间进行匹配的测试项,分别是-amin, -cmin, -mmin和-atime, -ctime, -mtime两组,第一组基于分钟,第二组基于天。
以-amin为例,假设当前时间tnow="2007-11-12 14:42:10"、t1="2007-11-12 14:39:10"、t2="2007-11-12 14:40:10",那么要查找最近访问时间属于[t1,t2]时间段的文件,可以这么写:
$ find . -amin 3
若测试项参数是数字,则基本上都可以在数字参数前加"+"或者"-"号,表示“大于”或“小于”的意思,因此,要查找最近访问时间属于[t1,tnow]时间段的文件,可以这么写:
$ find . -amin -3
"-amin n"和"-atime n"的处理方法都是:根据当前时间和文件的相应时间属性求n值,然后比较n值和参数n,看是否符合要求。但是这个求n值的过程却有很大不同,他们的不同也代表了两组(基于分钟和基于天)的不同:
"-amin n"
1、求Δt,用当前时间减去文件对应属性的时间值即得到Δt,Δt = tnow - tfile;
2、求浮点数f,用Δt除以1分钟,f = Δt / 1min;
3、将f的小数部分入到整数部分,得到n。即,不管f是6.0102还是6.8901,n都等于7
"-atime n"
1、求Δt,用当前时间减去文件对应属性的时间值即得到Δt,Δt = tnow - tfile;
2、求浮点数f,用Δt处以24小时,f = Δt / 24hours;
3、将f的小数部分都舍掉,得到n。即,不管f是6.0102还是6.8901,n都等于6
大家可以多做实验,试一下。
(八)权限位
很多人都在用windows,从windows系统拷过来的文件经常被加上了可执行权限,比如我现在想把主目录下所有的后缀名为.txt .pdf .rm并且具有可执行权限位的文件查找出来,该怎么写呢?
这里就不得不说一说权限位测试项:-perm。-perm支持符号权限位表示法也支持绝对(八进制)权限位表示法,但是最好使用八进制的权限表示法(这只是个建议 ^_^ )。
-perm基本上有下面这几中形式:
-perm mode File's permission bits are exactly mode.
-perm -mode All of the permission bits mode are set for the file.
-perm /mode Any of the permission bits mode are set for the file.
-perm +mode (此形式已经不推荐使用,功能与/mode相同)
好好理解上面蓝色部分,理解了,-perm测试项也就掌握了。
考考你:
看看下面这句话是什么意思?
find . -perm -444 -perm /222 ! -perm /111
现在再来解决本节最开始提出的问题:查找主目录下所有的后缀名为.txt .pdf .rm并且具有可执行权限位的文件。
$ find ~ \( -name "*.txt" -o -name "*.pdf" -o -name "*.rm" \) \
-not \( -type d -o -type l \) \
-perm /111 -print
(九)文件类型
有一个问题:我只想查找符号连接文件,可是查找结果中却包括了普通文件、目录文件等等,不相关的东西太多了,怎么把不是符号连接文件的查找结果去掉?
-type测试项刚好可以满足你的要求,-type c即可,其中c表示文件类型,find中支持如下类型:
b block (buffered) special
c character (unbuffered) special
d directory
p named pipe (FIFO)
f regular file
l symbolic link;
s socket
D door (Solaris)
针对上面的问题,可以这么写:
$ find . -name "e100*" -type l -print
./e1000
./e100puk.txt
但是,不要这么写:
$ find -L . -name "e100*" -type l -print
加上'-L'选项之后,你将查不到需要的东西,除非符号连接已经失效了。
(十)文件大小
前面一再使用-size测试项,这里简单介绍一下。
-size测试项根据文件的大小查找文件,文件大小既可以用块(block)来计量,也可以用字节来计量。默认情况下以块计量文件大小,若想使用字节来计量只需要在数字参数后加c即可。find支持的其他计量方式有:
-size n[cwbkMG],分别表示
‘b’ for 512-byte blocks (this is the default if no suffix is used)
‘c’ for bytes
‘w’ for two-byte words
‘k’ for Kilobytes (units of 1024 bytes)
‘M’ for Megabytes (units of 1048576 bytes)
‘G’ for Gigabytes (units of 1073741824 bytes)
(十一)用户、用户组
根据用户、用户组来查找文件,这个没有太多要说的,记住命令格式即可:
-uid n
-user username or uid
-nouser
-gid n
-group gname or gid
-nogroup
(十二)输出格式
如果你不想查找到你想要的文件事单调的输出文件名,你可以使用-printf动作项输出你想要的格式,下面举几个-printf动作的参数:
%p 输出文件名,包括路径名
%f 输出文件名,不包括路径名
%m 以8进制方式输出文件的权限
%g 输出文件所属的组
%h 输出文件所在的目录名
%u 输出文件的属主名
...
例如:
$ find . -user xixi -printf "%m %p \\n"
644 ./phone1/hello.c
644 ./0dfe.c
其余的,看man手册页吧。
(十三)执行外部命令
这又是一个很容易出彩的地方。find真是强大,对查找到的文件竟然可以调用外部命令进行处理。-exec动作项就是来完成这个功能的,格式是:
find . EXPR1 -exec command ...{} \;
注意:后一个花括号'}'和'\'之间有一个空格。
例如,查找当前目录下的所有普通文件,并用ls命令输出:
find . -type f -exec ls -l {} \;
有些操作系统中出于安全考虑只允许-exec选项执行诸如l s或ls -l这样的命令。
也可以使用-exec动作项的安全模式:-ok动作项。它的功能和语法都跟-exec一样,只不过它以更安全的模式运行,当要删除文件时,它会给出提示,让你选择到底删除还是不删。
例如:
$ find logs -name "*abc*" -ok rm {} \;
使用-exec动作项处理匹配到的文件时,find命令会将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。
xargs的使用格式是:
find PATH EXPR1 EXPR2 | xargs command
利用管道,把find命令匹配到的文件名传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。
在有些系统中,使用-exec动作项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高;而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。
例如,要在普通文件中查找文件内容中包含"io"的文件,可以这么写:
$ find . -type f | xargs grep "io"
Binary file ./a_book_of_c.chm matches
./2234.c:#include <stdio.h>
./3e10.c:#include <stdio.h>
find命令配合exec和xargs可以对所匹配到的文件执行几乎所有的命令。
(十四)总结
理解并运用find,关键是掌握find命令的处理规则(见第五节):递归遍历所指定的目录树,针对每个文件依次执行find命令中的表达式,表达式首先根据逻辑运算符进行结合,然后依次从左至右对表达式求值。把这个理解了,需要什么功能查一下man就可以了。
find命令还有好多功能这里没有涉及到,具体的大家看man手册页吧。在任何时候,man都是一个极好的帮助工具。 ^_^
(十五)附
第五节提出的问题,答案如下:
$ find . -size +0c -wholename "*e*[0-9]*" -o \
! \( -name "." -o -name "*phone" \) -prune -name "*.c" -user xixi \
-o -name "*phone"
./e1000
./e100.dat
./phone
./phone/e680gphone
./e100puk.txt
./3e10.c
./phone1
./phone1/hello.c
./phone2
./0dfe.c
./e680phone
这篇文章断断续续写了好久,今天终于基本完工。参考了man手册页以及一些网上的资料。
要把自己心中所想有条理的写出来感觉真是不易,希望对大家有所帮助。
欢迎批评指正。
Jakee
2007-11-12
find之强大毋庸置疑,此处只是带领大家一窥find门径,更详细的说明见man find和 info find。
整篇文章循序渐进,从最常用的文件名测试项开始步步深入,到第六节基本讲完find处理文件的规则,再之后的章节是一些常用表达式的说明。
(此篇中所有选项及例子基于GNU find version 4.2.28)
(一)Get Start
最简单的find用法莫过于如此:
$ find .
查找当前目录下的所有文件。
find命令的一般格式为:
find [-H] [-L] [-P] [path...] [expression]
其中,'-H' '-L' '-P'三个选项主要是用来处理符号连接,'-H'表示只跟随命令行中指定的符号连接,'-L'表示跟随所有的符号连接,'-P'是默认的选项,表示不跟随符号连接。
例如,在我的当前目录下有一个符号连接e1000,现在我想查找文件名中最后一个字母是数字的源文件,那么
$ find -H . -name "*[0-9].c" -print
./2234.c
像上面这样写只能查找出当前目录下符合要求的文件,却找不出e1000下的文件。因此可以这么写:
$ find -H e1000 . -name "*[0-9].c" -print
或者使用 '-L'选项
$ find -L . -name "*[0-9].c" -print
格式中的[path...]部分表示以此目录为根目录进行搜索。
格式中的[expression]是一个表达式。最基本的表达式分为三类:设置项(option)、测试项(test)、动作项(action),这三类又可以通过逻辑运算符(operator)组合在一起形成更大更复杂的表达式。设置项(如-depth,-maxdepth等)针对这次查找任务,而不是仅仅针对某一个文件,设置项总是返回true;测试项(test)则不同,它针对具体的一个文件进行匹配测试,如-name,-num,-user等,返回true或者false;动作项(action)则是对某一个文件进行某种动作(最常见的如-print),返回true或者false。
正是[expression]部分的丰富,才使得find如此强大。此部分较复杂,后面慢慢说明。
(二)文件名
根据文件名来查找一个文件是大家经常遇到的事情,第一节中的'-name'正是解决此问题的。
-name属于表达式中的测试项(test),它按照文件名模式来匹配文件,若匹配则返回true,否则返回false。最好用引号将文件名模式引起来,防止shell自己解析要匹配的字符串。(可以用单引号也可以用双引号,单引号和双引号在shell环境中的区别见后续部分)
例如,想要的当前目录及子目录中查找文件名以一个大写字母开头或者以小写a或b开头的文件,可以用:
$ find . -name "[A-Za-b]*" -print
./a_book_of_c.chm
./TMP1234
如果想在当前目录查找文件名不以大写字母开头,之后跟一个小写字母,再之后是两个数字,最后是.txt的文件,可以这么用:
$ find . -name "[^A-Z][a-z][0-9][0-9].txt" -print
./@y38.txt
注意:此处的模式匹配并不符合正则表达式。
-name对大小写字母敏感,如果想匹配时不考虑大小写可以使用-iname测试项。'i'可以加在许多选项前面,比如-ipath,-iregex,-iwholename等等,都是表示大小写不敏感。
(三)正则表达式
使用上面的-name测试项能解决许多问题,但是有些还是不太好办,比如:查找当前目录下名称全部为数字的c源代码文件,这时就该'-regex'出手了。正则表达式绝对值得你去好好研究一下,在unix系统下太有用了,这里不做过多说明,请读者自行学习。
-regex 同样属于测试项。使用-regex时有一点要注意:-regex不是匹配文件名,而是匹配完整的文件名(包括路径)。例如,当前目录下有一个文件"abar9",如果你用"ab.*9"来匹配,将查找不到任何结果,正确的方法是使用".*ab.*9"或者".*/ab.*9"来匹配。
针对上面的那个查找c代码的问题,可以这么写:
$ find . -regex ".*/[0-9]*\.c" -print
./2234.c
还有一个设置项(option)'-regextype',可以让你根据自己的喜好选择使用的正则表达式类型,大家可以试试。
(四)wholename与path
既然上一节提到了完整文件名(包括路径名),那么这里不妨说一下-wholename和-path。
-wholename和-path都属于测试项(test),而且功能也一样。-path从字面上看给人一种错觉,好像只匹配路径名(或者目录名),其实它也可以匹配文件名,因此-wholename这个名字更贴切一些。
看看这个例子,当前目录下有一个phone目录,phone目录里有一个文件名称是puk.txt,使用-path:
$ find . -path '*phone/pu*'
./phone/puk.txt
另外要提一点:使用-path的一般格式是:find [path ...] -path pattern ...
它的意思是:在[path ...]部分指明的路径上,使用pattern匹配所有文件的完整文件名;而不是说在类似的pattern目录下查找文件。
(五)逻辑运算符
有了上面三个选项,你现在应该对文件名的相关匹配得心应手了,对于不是很复杂的查找应该也胜任了。但是看看这个例子,解释一下它在做什么?
$ find . -size +0c -wholename "*e*[0-9]*" -o ! \( -name "." -o -name "*phone" \) -prune -name "*.c" -user xixi -o -name "*phone"
下面是当前目录下的所有文件:
$ ls -l
total 224
-rw-r--r-- 1 xixi admin 0 2007-11-01 17:34 0dfe.c
-rw-r--r-- 1 abc admin 0 2007-10-30 15:56 0s8a.txt
-rw-r--r-- 1 abc admin 0 2007-11-04 01:00 0TMP123
-rw-r--r-- 1 abc admin 73 2007-11-05 15:33 2234.c
-rw-r--r-- 1 abc admin 72 2007-11-05 15:34 3e10.c
-rw------- 1 abc admin 224017 2006-03-16 12:16 a_book_of_c.chm
lrwxrwxrwx 1 abc admin 15 2007-11-04 11:48 e1000 -> ../e1000-7.6.9/
-rw-r--r-- 1 abc admin 70 2007-11-05 14:57 e100.dat
lrwxrwxrwx 1 abc admin 13 2007-11-05 14:59 e100puk.txt -> phone/puk.txt
-rw-r--r-- 1 abc admin 0 2007-11-06 22:21 e680phone
drwxr-xr-x 2 abc admin 37 2007-11-06 22:24 phone
drwxr-xr-x 2 abc admin 20 2007-11-07 01:07 phone1
drwxr-xr-x 2 abc admin 6 2007-11-05 15:37 phone2
-rw-r--r-- 1 abc admin 67 2007-11-04 12:23 @y38.txt
phone$ ls -l
total 4
-rw-r--r-- 1 abc admin 0 2007-11-06 22:24 e680gphone
-rw------- 1 abc admin 38 2007-11-05 14:58 puk.txt
phone1$ ls -l
total 0
-rw-r--r-- 1 xixi admin 0 2007-11-07 01:07 hello.c
phone2$ ls -l
total 0
要想解决上面的问题就得学习一下find中的逻辑运算符。逻辑运算符主要有以下几个,按照优先级从高到低的顺序如下:
( expr )
括号优先级最高,首先对括号内的求值
! expr
对expr表达式的值取反
-not expr
同上,但是POSIX不支持
expr1 expr2
不加任何运算符,相当于两个之间加and,即与运算,两个表达式值都为true整个才返回true。先对expr1表达式求值,若为false,则不对expr2求值。
expr1 -a expr2
同上
expr1 -and expr2
同上,但是POSIX不支持
expr1 -o expr2
表示对expr1和expr2两个表达式的值求或,左右两个值只要有一个为ture,整个表达式就是true。先对expr1表达式求值,若为ture,则不对expr2求值。
expr1 -or expr2
同上,但是POSIX不支持
expr1 , expr2
逗号表达式。expr1和expr2都会求值,但是只返回expr2的值,expr1的值会被丢弃
正是因为有一个求值的顺序,所以你才有可能见到这样的写法:
$ find . -name "*.txt" -o -print
表示,如果表达式-name "*.txt"为真,就不再执行另一个表达式-print,即查找所有不是以.txt结尾的文件。
再有,要查找当前目录下,文件名中包括字母'e',在'e'之后又有数字的不是目录文件的所有文件,可以这么写:
$ find . -name "*e*[0-9]*" ! -type d -print
./e1000
./e100.dat
./e100puk.txt
./3e10.c
大家可以自己多举几个例子试一下。
(六)-prune
-prune是一个动作项,它表示当文件是一个目录文件时,不进入此目录进行搜索。
要理解-prune动作,首先得理解find命令的搜索规则(也可以说find命令的算法)。
find命令递归遍历所指定的目录树,针对每个文件依次执行find命令中的表达式,表达式首先根据逻辑运算符进行结合,然后依次从左至右对表达式求值。以下面代码为例,进行说明
find PATHP1 OPT1 TEST1 ACT1 ( TEST2 or TEST3 ) ACT2
(1) 根据OPT1设置项进行find命令的整体设置,若没有-depth设置项,依次进行下面的步骤
(2) 令文件变量File = PATHP1
(3) 对File文件进行TEST1测试,若执行结果为false,转(8)
(4) 对File文件进行ACT1动作,若执行结果为false,转(8)
(5) 对File文件进行TEST2测试,若执行结果为true,转(7)
(6) 对File文件进行TEST3测试,若执行结果为false,转(8)
(7) 对File文件进行ACT2动作
(8) 若File文件是一个目录,并且没有被执行过-prune动作,则进入此目录
(9) 当前目录下是否还有文件,若有依次取一个文件,令File指向此文件,转(3);
(10) 判断当前目录是否是PATHP1,若是则程序退出;若不是,则返回上一层目录,转(9)
理解了上面的流程,那么不难理解下面的代码为什么只输出一个'.'
$ find . -prune
.
再有,当前目录下大于4090字节的文件有两个,而大于4096字节的文件只有一个,如下:
$ find . -size +4090c -print
.
./a_book_of_c.chm
$ find . -size +4096c -print
./a_book_of_c.chm
那么,将上面两个-print都替换为-prune,这两条命令分别输出什么?
$ find . -size +4090c -prune
.
$ find . -size +4096c -prune
./a_book_of_c.chm
这就是答案,如果你答对了,恭喜你,你已经掌握了find命令!
-prune经常和-path或-wholename一起使用,以避开某个目录,常见的形式是:
$ find PATH (-path <don't want this path #1> -o -path <don't want this path #2>) -prune -o -path <global expression for what I do want>
注意:如果同时使用-depth设置项,那么-prune将被find命令忽略。man手册页中这么说:"If -depth is given, false; no effect."
说到这里,又得说说-depth设置项。网上好多资料说-depth设置项的功能是“在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找”,这明显是错误的,man手册页中如是说:"-depth Process each directory's contents before the directory itself."。这有点像树的后序遍历,先遍历当前节点的所有子节点,然后再访问当前节点...
考考你:
下面的命令输出什么?为什么?
$ find . -depth -prune -name "*.c" -print
(七)时间戳
理解了上面几节,你已经掌握了find命令的“道” ^_^ ,下面这几节只是介绍一些常用、好用的“招式”。这一节介绍时间戳。
文件有三个时间属性:创建时间、最近修改时间、最近访问时间。
最近修改时间又包括两种,一是文件的状态(也即权限如rwx等)最近被修改时间,一是文件的数据(也即内容)最近被修改时间。touch命令改变的即是文件数据最近被修改时间。
最近访问时间,指的是最近一次文件数据(内容)被访问的时间。因此,使用ls命令输出文件的相关信息并不会修改文件的最近访问时间。
find命令提供了针对文件的最近访问时间、文件状态最近被修改时间、文件数据最近被修改时间进行匹配的测试项,分别是-amin, -cmin, -mmin和-atime, -ctime, -mtime两组,第一组基于分钟,第二组基于天。
以-amin为例,假设当前时间tnow="2007-11-12 14:42:10"、t1="2007-11-12 14:39:10"、t2="2007-11-12 14:40:10",那么要查找最近访问时间属于[t1,t2]时间段的文件,可以这么写:
$ find . -amin 3
若测试项参数是数字,则基本上都可以在数字参数前加"+"或者"-"号,表示“大于”或“小于”的意思,因此,要查找最近访问时间属于[t1,tnow]时间段的文件,可以这么写:
$ find . -amin -3
"-amin n"和"-atime n"的处理方法都是:根据当前时间和文件的相应时间属性求n值,然后比较n值和参数n,看是否符合要求。但是这个求n值的过程却有很大不同,他们的不同也代表了两组(基于分钟和基于天)的不同:
"-amin n"
1、求Δt,用当前时间减去文件对应属性的时间值即得到Δt,Δt = tnow - tfile;
2、求浮点数f,用Δt除以1分钟,f = Δt / 1min;
3、将f的小数部分入到整数部分,得到n。即,不管f是6.0102还是6.8901,n都等于7
"-atime n"
1、求Δt,用当前时间减去文件对应属性的时间值即得到Δt,Δt = tnow - tfile;
2、求浮点数f,用Δt处以24小时,f = Δt / 24hours;
3、将f的小数部分都舍掉,得到n。即,不管f是6.0102还是6.8901,n都等于6
大家可以多做实验,试一下。
(八)权限位
很多人都在用windows,从windows系统拷过来的文件经常被加上了可执行权限,比如我现在想把主目录下所有的后缀名为.txt .pdf .rm并且具有可执行权限位的文件查找出来,该怎么写呢?
这里就不得不说一说权限位测试项:-perm。-perm支持符号权限位表示法也支持绝对(八进制)权限位表示法,但是最好使用八进制的权限表示法(这只是个建议 ^_^ )。
-perm基本上有下面这几中形式:
-perm mode File's permission bits are exactly mode.
-perm -mode All of the permission bits mode are set for the file.
-perm /mode Any of the permission bits mode are set for the file.
-perm +mode (此形式已经不推荐使用,功能与/mode相同)
好好理解上面蓝色部分,理解了,-perm测试项也就掌握了。
考考你:
看看下面这句话是什么意思?
find . -perm -444 -perm /222 ! -perm /111
现在再来解决本节最开始提出的问题:查找主目录下所有的后缀名为.txt .pdf .rm并且具有可执行权限位的文件。
$ find ~ \( -name "*.txt" -o -name "*.pdf" -o -name "*.rm" \) \
-not \( -type d -o -type l \) \
-perm /111 -print
(九)文件类型
有一个问题:我只想查找符号连接文件,可是查找结果中却包括了普通文件、目录文件等等,不相关的东西太多了,怎么把不是符号连接文件的查找结果去掉?
-type测试项刚好可以满足你的要求,-type c即可,其中c表示文件类型,find中支持如下类型:
b block (buffered) special
c character (unbuffered) special
d directory
p named pipe (FIFO)
f regular file
l symbolic link;
s socket
D door (Solaris)
针对上面的问题,可以这么写:
$ find . -name "e100*" -type l -print
./e1000
./e100puk.txt
但是,不要这么写:
$ find -L . -name "e100*" -type l -print
加上'-L'选项之后,你将查不到需要的东西,除非符号连接已经失效了。
(十)文件大小
前面一再使用-size测试项,这里简单介绍一下。
-size测试项根据文件的大小查找文件,文件大小既可以用块(block)来计量,也可以用字节来计量。默认情况下以块计量文件大小,若想使用字节来计量只需要在数字参数后加c即可。find支持的其他计量方式有:
-size n[cwbkMG],分别表示
‘b’ for 512-byte blocks (this is the default if no suffix is used)
‘c’ for bytes
‘w’ for two-byte words
‘k’ for Kilobytes (units of 1024 bytes)
‘M’ for Megabytes (units of 1048576 bytes)
‘G’ for Gigabytes (units of 1073741824 bytes)
(十一)用户、用户组
根据用户、用户组来查找文件,这个没有太多要说的,记住命令格式即可:
-uid n
-user username or uid
-nouser
-gid n
-group gname or gid
-nogroup
(十二)输出格式
如果你不想查找到你想要的文件事单调的输出文件名,你可以使用-printf动作项输出你想要的格式,下面举几个-printf动作的参数:
%p 输出文件名,包括路径名
%f 输出文件名,不包括路径名
%m 以8进制方式输出文件的权限
%g 输出文件所属的组
%h 输出文件所在的目录名
%u 输出文件的属主名
...
例如:
$ find . -user xixi -printf "%m %p \\n"
644 ./phone1/hello.c
644 ./0dfe.c
其余的,看man手册页吧。
(十三)执行外部命令
这又是一个很容易出彩的地方。find真是强大,对查找到的文件竟然可以调用外部命令进行处理。-exec动作项就是来完成这个功能的,格式是:
find . EXPR1 -exec command ...{} \;
注意:后一个花括号'}'和'\'之间有一个空格。
例如,查找当前目录下的所有普通文件,并用ls命令输出:
find . -type f -exec ls -l {} \;
有些操作系统中出于安全考虑只允许-exec选项执行诸如l s或ls -l这样的命令。
也可以使用-exec动作项的安全模式:-ok动作项。它的功能和语法都跟-exec一样,只不过它以更安全的模式运行,当要删除文件时,它会给出提示,让你选择到底删除还是不删。
例如:
$ find logs -name "*abc*" -ok rm {} \;
使用-exec动作项处理匹配到的文件时,find命令会将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是xargs命令的用处所在,特别是与find命令一起使用。
xargs的使用格式是:
find PATH EXPR1 EXPR2 | xargs command
利用管道,把find命令匹配到的文件名传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。
在有些系统中,使用-exec动作项会为处理每一个匹配到的文件而发起一个相应的进程,并非将匹配到的文件全部作为参数一次执行;这样在有些情况下就会出现进程过多,系统性能下降的问题,因而效率不高;而使用xargs命令则只有一个进程。另外,在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。
例如,要在普通文件中查找文件内容中包含"io"的文件,可以这么写:
$ find . -type f | xargs grep "io"
Binary file ./a_book_of_c.chm matches
./2234.c:#include <stdio.h>
./3e10.c:#include <stdio.h>
find命令配合exec和xargs可以对所匹配到的文件执行几乎所有的命令。
(十四)总结
理解并运用find,关键是掌握find命令的处理规则(见第五节):递归遍历所指定的目录树,针对每个文件依次执行find命令中的表达式,表达式首先根据逻辑运算符进行结合,然后依次从左至右对表达式求值。把这个理解了,需要什么功能查一下man就可以了。
find命令还有好多功能这里没有涉及到,具体的大家看man手册页吧。在任何时候,man都是一个极好的帮助工具。 ^_^
(十五)附
第五节提出的问题,答案如下:
$ find . -size +0c -wholename "*e*[0-9]*" -o \
! \( -name "." -o -name "*phone" \) -prune -name "*.c" -user xixi \
-o -name "*phone"
./e1000
./e100.dat
./phone
./phone/e680gphone
./e100puk.txt
./3e10.c
./phone1
./phone1/hello.c
./phone2
./0dfe.c
./e680phone
这篇文章断断续续写了好久,今天终于基本完工。参考了man手册页以及一些网上的资料。
要把自己心中所想有条理的写出来感觉真是不易,希望对大家有所帮助。
欢迎批评指正。
Jakee
2007-11-12
发表评论
-
thinkpad小红帽+中键滚屏
2011-02-04 19:05 3014由于习惯了不使用鼠标,windows下一直用的小红帽+中键滚屏 ... -
win7 下恢复 ubuntu 10.04(转)
2010-11-08 16:04 1715转自:http://www.cppblog.com/guoji ... -
realplayer 自动退出
2009-11-27 13:19 1137从官网下载了realplayer的deb包,安装完毕,播放文件 ... -
Linux歌词显示
2009-11-09 14:28 941安装附件里的包,然后: 首先项-->插件-->常规--> ... -
Ubuntu g2ipmsg
2009-11-09 09:46 1331本方转自“http://forum.ubuntu.org.cn ... -
几个常用的Firefox插件
2009-09-14 13:46 820上传几个常用的Firefox插件,下次重装系统找起来就不用这么 ... -
Ubuntu 8.04 无法启动openoffice.org
2009-09-14 13:31 1465今天把ubuntu 从7.10 升级到 8.04,打开OPEN ... -
Linux CGI编程
2009-03-22 16:46 1988转自http://blog.chinaunix.net ... -
Linux下MP3歌曲信息乱码之贱人解决方案
2009-03-20 22:51 1398转载一篇文章: 现在linux下有越来越多的优秀的播放软件 ... -
ubuntu 飞信插件安装
2009-03-20 22:07 1646一,安装pidgin sudo apt-get install ... -
Wget使用方法
2009-03-20 08:13 1471本文转自 http://wiki.ubuntu ... -
UbuntuSkills
2009-03-20 08:09 1013本文转自 http://wiki.ubuntu.org.cn/ ... -
Opera 9.64 输入法无效解决方案
2009-03-17 09:04 998用OPERA也用一段时间了,前阵子升级到Opera 9.64, ... -
替换^M字符
2009-03-17 09:00 2395最近经常在LINUX下C编程,使用vi来查看一些在Window ... -
java MD5加密类--笔记
2009-02-22 13:13 1733java MD5加密类--笔记 转 ... -
Ubuntu TELNET服务安装配置
2008-12-31 12:28 2263Ubuntu TELNET服务安装配置 1. sudo a ... -
find命令详解。非常详细有用
2008-12-30 13:59 2835今天进行些文件处理时要用到find命令,网上搜索后发现下面的文 ... -
用iconv批量转换文本编码,解决showlyric乱码问题
2008-12-30 13:50 3618问题:想在ubuntu下听音乐不难,但想让它同时显示歌词却不容 ... -
解决Rhythmbox乱码
2008-12-29 12:53 4795今天在ubuntu论坛看到怎样解决困惑我已久Rhythmbox ... -
adobe reader 中文语言包的安装问题
2008-12-26 14:11 3578以前安装了Adobe reader,打开中文PDF从未出现问题 ...
相关推荐
### Linux Find 命令详解 #### 一、前言:了解 find 命令 `find` 是 Linux 和类 Unix 系统中一个非常强大的工具,用于在文件系统中搜索文件。它提供了多种选项来根据不同的标准进行精确查找,如文件名、权限、拥有...
超级详细的Linux,find命令详解,很实用适合Linux学习爱好者!
Linux Find命令是Linux系统中一个极其重要的工具,它允许用户在文件系统中查找符合特定条件的文件和目录。这个命令的灵活性和强大性使得它成为系统管理员和开发者的必备技能。下面将详细介绍Linux Find命令的一些...
《Linux命令详解词典》是由施威铭研究室编著的一本详尽解析Linux命令的参考书籍,旨在帮助用户深入理解和掌握Linux操作系统中的各种命令。这本书以扫描版的形式提供,包含PDF格式,方便读者在线阅读或下载。标签...
这份“Linux命令详解词典”由施威铭研究室提供,涵盖了Linux系统下的所有基本及高级操作命令,对于学习和理解Linux系统的管理至关重要。下面将详细阐述一些关键的Linux命令。 1. **ls**:列出目录内容。`ls`命令...
### Linux Find 命令使用手册详解 #### 概述 `find` 是一个功能强大的命令行工具,用于在Linux系统中的目录树中查找文件。它支持多种选项和表达式来帮助用户根据特定条件筛选出目标文件。此文档将详细介绍`find`...
### Linux之find命令详解 #### 一、find命令概述 `find`命令是Linux系统中最常用的文件搜索工具之一,能够帮助用户根据不同的条件查找文件或目录。这些条件包括但不限于文件名、类型、大小、权限、拥有者等。通过...
### Linux Find 命令详解 #### 概述 `find` 命令是 Linux 系统中一个非常强大的工具,用于在指定路径下查找文件。它支持多种选项来帮助用户精确地定位到需要的文件。通过 `find` 命令,用户可以基于文件名、文件...
Linux 下 find 命令详解 find 命令是 Linux 系统中一个功能强大且常用的命令,用于在文件系统中搜索文件。它可以根据文件的各种属性,如名称、权限、所有者、组、时间戳、大小等,来查找指定的文件。 基本语法 ...
### Linux常用命令详解知识点 #### 一、命令格式与通配符 - **命令格式**: - **命令**:指定要执行的操作。 - **选项**:改变命令的行为方式,通常以`-`开头,多个选项可以用空格或直接连接的方式给出。 - **...
### Linux Find 命令使用详解 #### 一、前言与概述 `find` 是 Linux 下一个极其强大且多功能的文件查找工具。它能够帮助用户根据不同的标准(如文件名称、所有者、修改时间等)查找文件。尤其是在管理大型文件系统...
### Linux Find 命令详解 #### 概述 `find` 命令是 Linux 系统中一个非常强大的工具,用于在指定目录及其子目录下查找文件或目录。通过使用不同的选项,用户可以非常精确地定位到所需的文件。 #### 基本语法 ```...
本文将深入探讨“Linux命令大全详解”这一主题,帮助读者掌握Linux操作系统的精髓,提升日常工作效率。 首先,Linux命令行是Linux系统中最基础且强大的工具。它允许用户通过输入命令来执行各种任务,如文件管理、...
大数据基础-Linux基础详解课程
### Linux网卡驱动详解——Realtek 8139实例 #### 一、引言 在深入探讨Linux网卡驱动的开发之前,我们先来简要回顾一下驱动程序的重要性及其在操作系统中的作用。驱动程序是一种特殊的软件,它作为硬件与操作系统...
在Linux系统中,`find`命令是一个非常实用的工具,用于在文件系统中搜索指定的文件或目录。它提供了丰富的参数,可以根据文件的名称、类型、大小、时间戳等多种属性进行筛选。下面我们将详细讲解`find`命令的用法。 ...
本《Linux命令详解手册》正是针对这一主题进行深入探讨的资源。 Linux命令是操作系统与用户交互的基本工具,通过输入简单的命令,用户可以实现文件操作、系统管理、网络通信等诸多功能。了解和熟练掌握这些命令对于...
### Linux正则表达式详解 在Linux环境下,正则表达式是一种非常强大的文本处理工具,广泛应用于各种场景,如文件搜索、数据匹配等。本文将详细介绍Linux正则表达式的使用方法及其背后的逻辑。 #### 正则表达式基础...
"Linux 命令详解手册中文版"正是为初学者提供的一份实用指南,帮助他们快速入门Linux世界。 1. **基础命令**: - **ls**:列出目录内容,用于查看当前目录下的文件和子目录。 - **cd**:改变工作目录,用于在文件...