寻觅生命中的那一片浅草......

使用find命令

find最简单的应用,是搜索当前目录及其子目录下的文件。

$ find .
./tp1301.txt
./up1301.txt
./tp1302.txt
./up1302.txt
./Up1303.txt
./misc/uploads
./misc/uploads/patch12_13.diff

像往常一样,那个点(.)代表当前目录。在以上例子里,find列出了当前目录及其子目录下的所有文件。

如果只想搜索up开头的文件名,使用’-name’参数。

也就是如下命令:

$ find . -name up*
./up1301.txt
./up1302.txt
./misc/uploads

find默认是大小写敏感的。如果想让find找到’p1303.txt’文件,要么使用’find -name UP*’,要么就用’iname’参数代替’name’参数。

通配符前的斜线是转义符,这样Bash才会把字面意义的星号传递给find作为参数,而不是首先把文件名扩展,再将扩展之后的那些文件名传递给find作为参数。

这个技巧很重要。要注意那些在shell里有特殊意义的字符。

我们也可以列出当前目录中以大小写不敏感的up(up, Up, uP, UP)开头,其中非小写up的文件名。

$ find -iname up* -not -name up*

操作符

find使用-and,-or,和-not参数支持布尔代数值。它们也可以分别缩写成-a,-o和!(在bash中必须使用!进行转义)。或(and)操作符在此提及,只是内容完整的需要。它是默认就在使用的:

$ find . -iname david*gray*ogg -type f > david_gray.m3u

上例中的操作符将按如下顺序处理:

() 圆括号用圆括号强制执行顺序提前。

-not 反转测试表达式的结果。

-and 如ex1 -and ex2;如果第一个表达式为假,将不再执行第二个表达式。

-or 如ex1 -or ex2;如果第一个表达式为真,将不再执行第二个表达式。

‘,’ 这是列表操作符(list operator)。不像-and和-or,它将使两个表达式都执行。在‘2 into 1 does go’部分有更多信息。

之前的那个例子将创建一个m3u播放列表,列出所有的以’David Gray’开头的ogg文件。(大小写不敏感)

$ find . -iname david gray*ogg -type f > david_gray.m3u

这个例子则将找出所有叫”david gray…ogg”的文件,照样大小写不敏感。

下例在语义上与上例等同:

$ find . -iname david gray*ogg -and -type f > david_gray.m3u

下例与上两例的语义等同:

$ find . -iname “david gray*ogg” -and -type f > david_gray.m3u

如果艺术家’David Gray’的名字有可能在文件名里,也有可能在子目录名里,怎样找到它们呢?

$ find . -ipath *david gray*ogg -type f > david_gray.m3u

表达式以星号通配符开头,因为可能有不止一个的叫’david gray’的子目录仅仅是为了分类的符号链接。(GNU find中此语句必须以*开头,是因为不这样的话,就没有结果。并且-type f代表的是普通文件,-type l才是符号链接。所以,不知道作者说的什么意思。并且GNU find反对使用-ipath参数,应当使用的是-iwholename。)

这有另一个例子,我们将列出humour目录的内容(一行一个文件),然后搜索有大小写不敏感的’yodo’在文件名中的.mp3文件。

$ ls humour -1
Weird Al – Yoda.mp3
welcome_to_the_internet_helpdesk.mp3
werid al – livin’ la vida yoda.mp3

$ find -ipath *humour*yoda* -type f
./humour/Weird Al – Yoda.mp3
./humour/werid al – livin’ la vida yoda.mp3

合并任务

在操作符一节就已经暗示了,可以用find一次执行多次任务。

下例创建两个列表文件,一个包括所有的.php文件,另一个包括所有.js文件。-fprint参数表示把搜索结果输出到文件中。

$ find ~ -type f ( -name *.php -fprint php_files , -name *.js -fprint javascript_files )

剪切

假设您想创建一个播放列表文件列出所有David Gray的.ogg文件,但是有些专辑你不想包括在内。

您可以用-prune参数阻止这些专辑出现在播放列表中,-prune参数匹配不包含某个表达式的目录或文件名。

下例能将Flesh和Lost Songs专辑排除:

$ find ( -path ./mp3/David_Gray/Flesh* -o -path “./mp3/David_Gray/Lost Songs” * ) -prune -o -ipath *david gray*

首先,您会注意到被转义的圆括号,这样bash才不会误用它们。使用-prune参数,意思就是”别找这些,去找其他的“。

$ find (-path <don’t want this> -o -path <don’t want this#2>)
-prune -o -path <global expression for what I do want>

可能需要较长的时间才能掌握-prune参数的使用:首先要确定你究竟想使用它做什么。我发现使用-prune参数能省下不少时间让我去完成其他任务。
其他参数

还有许多其他表达式和参数可供find使用。

这有一些可能是您最想使用的:

-nouser 拥有文件的用户不在/etc/passwd文件中。

-nogroup 拥有文件的组不在/etc/groups文件中。

-owner <username> 指定用户拥有的文件。

我们将在稍后再研究这些参数以及其他一些参数的使用。
输出方式
改变输出信息

如果您输出的不仅仅是文件名,-printf参数可以输出任何种类你想要的信息。去看看手册页,那里有惊人多的选项。

以下这些可能是使用最多的:

%p 文件名,名字中包括其所在的目录,也即是路径名(path)。

%m 文件的权限,以数字显示。

%f 文件名,不包括所在目录。

%g 文件所属组名。

%h 显示文件所在目录。

%u 文件所属用户名。

如下例:

$ find . -name *.ogg -printf %f

将生成一个包含所有当前目录及其子目录想的.ogg文件列表。

‘ ‘前的反斜线很重要,’ ‘代表开始新一行。’n’之前的反斜线必须被转义,否则命令行解释器将会首先使用’ ‘。
输出到哪里

find有一些参数控制输出信息写入到任何您想写入的文件。它们使-fprint,-fprint0,-fprintf参数。

$ find . -iname david gray*ogg -type f -fprint david_gray.m3u

这样,上例比下例更有效。

$ find . -iname david gray*ogg -type f > david_gray.m3u

执行命令

文件是生成基本信息报告的很好工具,但是如果你想要的不仅仅是报告呢?你可以把标准输出用管道重定向给其他工具。

$ find ~/oggs/ -iname *.mp3 | xargs rm

不过,这并不总是那么有效。

最好还是使用-exec参数。

$ find ~/oggs/ -iname *.mp3 -exec rm {} ;

也许这个例子比较难看懂,它的意思是搜索到这些文件后便立即将其删除。

‘{}’是一个代表找到的所有文件的占位符,’;’必须被转义,以免bash误用。

谨慎起见,-ok参数可以代替-exec。-ok参数会在执行命令之前请就确认。

这有许多种方法可以用到日常真实情况中。

比如,你的默认Mozilla配置文件被锁定了,下例可以帮你解锁。(删除lock文件即可)

$ find ~/.mozilla -name lock -exec rm {} ;

压缩当前及其子目录下所有日志文件:

$ find . -name *.log -exec bzip {} ;

将当前及其子目录下所有无有效用户权限的文件的权限赋予给用户ken。

$ find . -nouser -exec chown ken {} ;

用vim打开所有当前目录下的.dat文件,不搜索子目录。

$ vim -R `find . -name *.dat -maxdepth 1`

在当前目录中至少四层以下(包括四层)的子目录中搜索目录名CVS。

$ find -mindepth 4 -type d -name CVS

创建时间

也许您想搜索最近创建的文件,或者查找近三天内的日志文件中的字符串。

这是find所擅长的:它可以根据文件的时间戳来限制搜索的范围。

假设您想找到您主目录中近五天内修改过的隐藏文件:

$ find ~ -mtime -5 -name .*

如果你知道某个文件在更近的时间内修改过,例如14分钟内,可用如下参数:

$ find ~ -mmin -14 -name .*

注意,列出文件(ls)的操作会影响文件的访问时间戳。如果你先做一次列出文件(ls)的操作,然后再使用上例中的命令,所有的文件都会列出。(不知道作者用的是什么版本的find。GNU find 4.32是区别amin(access)和mmin(modify)的,上例仍有效)

要找到那些在某个时间点之后修改过的文件,可以使用下例中的技巧:

$ touch -d “13 may 2001 17:54:19” date_marker
$ find . -newer date_marker

要找到创建于上例中时间点之前的文件,使用’cnewer’加否定式:

$ find . ! -cnewer date_marker

找出昨天里修改过的文件:

$ find . -daystart -atime 1 -maxdepth

‘-daystart’参数意思是时间从今天的开端(也即今日之零点)开始计算,而不是从当前时间点开始计算。

这个参数只对’-amin’、’-atime’、’-cmin’、’ctime’、’mmin’和’mtime’选项有效。
文件大小
字符文件

要找出有含有指定数量字符的文件,您能错过这节。

找出有正好有1000个字符的文件:

$ find . -size 1000c

找出有600到700个字符的文件,600和700包含在内:

$ find . -size +599c -and -size -701c

字符(character)其实是误称:’c’在find中是字节(byte)意思;所以这些命令只能作用于ASII文件,对Unicode文件无用。

参考用户手册,我们可以看到:

c = 字节 bytes w = 2字节 2 byte words k = 千字节 kilobytes b = 512字节的块 512-byte blocks

这样我们可以用find来找出指定大小的文件:

$ find /usr/bin -size 48k

空文件

你可以用下例找到空文件:

$ find . -size 0c

用-empty参数更有效。

删除当前目录下所有空文件:

$ find . -empty -maxdepth 1 -exec rm {} ;

用户和组
用户

搜索属于指定用户的文件:

# find /etc -type f !  -user root -exec ls -l {} ;
-rw——- 1 lp sys 19731 2002-08-23 15:04 /etc/cups/cupsd.conf
-rw——- 1 lp sys    97 2002-07-26 23:38 /etc/cups/printers.conf

如果只需要上面列出信息的子集的话,就没必要使用exec:

root@ttyp0[etc]# find /etc -type f !  -user root -printf “%h/%f %u”
/etc/cups/cupsd.conf lp
/etc/cups/printers.conf lp

如果您只知道用户id(uid),而不知道用户名的话,可以用’-uid’参数:

$ find /usr/local/htdocs/www.linux.ie/ -uid 401

‘-nouser’参数意思是所有在/etc/passwd文件中的用户都不拥有所要搜索的文件。

也可以搜索属于或不属于指定组的文件,取决您如何使用它。

这非常适合用来搜索那些本该属于www组,但却不属于的文件:

$ find /www/ilug/htdocs/  -type f ! -group  www

‘-nogroup’参数意思是所有在/etc/group文件中的组都不拥有所要搜索的文件。

如果某个组使用过一段时间后被删除了,这个参数就有用了。

用’gid’参数搜索属于指定gid的文件。

$ find -gid 100

权限

如果您曾经因为权限设置问题而无法运行一些脚本,并且您想一次性解决这个问题,那您应该看下面这个小例子:

knoppix@ttyp1[bin]$ ls -l ~/bin/
total 8
-rwxr-xr-x    1 knoppix  knoppix        21 2004-01-20 21:42 wl
-rw-r–r–    1 knoppix  knoppix        21 2004-01-20 21:47 ww

knoppix@ttyp1[bin]$ find ~/bin/ -maxdepth 1 -perm 644 -type f -not -name .*
/home/knoppix/bin/ww

找出所有没有执行权限(644)的文件,就像我们在输出中看到的。
文件类型

‘-type’参数明显是用来指定寻找什么类型的文件的(记住,在Linux下,一切东西都是某种文件)。

目前为止,我用过’-type f’来寻找普通文件。

如果我们想找到有’_of_’在其文件名中的目录,可以用:

$ find . -type d -name ‘*_of_*’

上例中的输出不会包括指向目录的符号链接。

如果想包括目录和指向目录的符号链接,请用:

$ find . ( -type d -or -type l ) -name ‘*_of_*’

参考用户手册,以获得所有文件类型的完成列表。

正则表达式

我们已经偶尔使用过通配符来指定一组文件。find也支持正则表达式,所以我们也可以使用更复杂的规则来指定要搜索的文件。正则表达式会以整个路径为匹配对象:

ken@gemmell:/home/library/src$ find . -regex ‘.*/mp[0-4].*’
./library/sql/mp3_genre_types.sql

‘-regex’的大小写不敏感的形式是’-iregex’。

使用正则表达式的技巧是:注意匹配的是文件的绝对路径,即使是在搜索当前文件文件夹。如:

$ cd /usr/share/doc/samba-doc/htmldocs/using_samba
$ find . -regex ‘./ch0[1-2]_0[1-3].*’
./ch01_01.html
./ch01_02.html
./ch02_01.html
./ch02_02.html
./ch02_03.html

文件系统

使用root用户将一个微软格式的软盘挂载起来做一个实验:

$ su –
# mount /floppy
# mount
/dev/sda2 on / type ext2 (rw,errors=remount-ro)
proc on /proc type proc (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
/dev/fd0 on /floppy type msdos (rw,noexec,nosuid,nodev)

然后试如下命令:

$ find / -fstype msdos -maxdepth 1

您应该只看到/floppy列出来。

要得到想反的结果,比如列出不在msdos文件系统上的文件,可用:

$ find / -maxdepth 1 ( -fstype msdos ) -prune -or -print

这只是对指定文件系统来搜索文件的一个简单介绍。
总结

我已经介绍了非常多的find工具的功能,但这并不是全部。如果您有任何问题,不要犹豫,您可以给我发邮件。

转载自:http://www.yeeyan.com/articles/view/kyl/6037

尚无评论

发表评论

2024年四月
« 5月    
1234567
891011121314
15161718192021
22232425262728
2930