find命令详解
1. find命令简介
find命令主要用于文件搜索,它的功能非常强大,可以根据不同的标准搜索任何文件,可以在任何位置进行检索。find命令的主要格式如下:
find path test action
(1)path表示要搜索的路径,可以同时指定多个路径,路径之间以空格隔开:
find /user/bin #搜索/user/bin目录和子目录
find / #搜索根目录及子目录(实际上就是搜索整个文件系统)
find . #搜索当前目录
find -root #搜索root用户的主目录
find /user/bin /home #搜索/user/bin和/home目录及它们的子目录
(2)test表示测试条件,用户可以指定多个测试条件来查找符合特定标准的文件,条件之间以空格隔开:
find / -type f #搜索的文件类型:f=file d=directory
find / -name "*.txt" #搜索文件名后缀为txt,*为通配符
下面是详细测试条件表:
条件 | 说明 |
---|---|
-name pattern | 表示包含指定匹配模式的文件名,区分大小写 |
-type pattern | 指定文件类型 |
-perm mode | 匹配权限被设置为指定mode的文件 |
-user userid | 匹配所有者为指定用户id的文件< |
-group groupid | 匹配所有者的主组为指定组id的文件 |
-size size | 匹配大小为size的文件 |
-empty | 匹配空文件 |
-amin [-+]n | 文件最后一次访问时间,-n表示访问时间为距今n分钟以内,+n表示访问时间为距今n分钟以前,n表示恰好n分钟 |
-atime [-+]n | 文件最后一次访问时间,时间单位为天 |
-cmin [-+]n | 文件最后一次状态改变的时间,时间单位为分钟 |
-ctime [-+]n | 文件最后一次状态改变的时间,时间单位为天 |
-mmin [-+]n | 文件最后一次被修改的时间,时间单位为分钟 |
-mtime [-+]n | 文件最后一次被修改的时间,时间单位为天 |
(3)action表示对find结果执行操作。
|动作|说明|
|------ -----------|:----------------------------|
|-print|默认动作,将结果写入到标准输出|
|-fprint file|将结果写入到文件file|
|-ls|以详细格式显示搜索结果|
|-fls file|将详细格式的结果写入到文件file|
|-delete|将搜索到的文件删除<|
|-exec command {} ;|查找并执行命令,{}表示搜索到的文件名|
|-ok command {} ;|查找并执行命令,但是需要用户确认|
-exec
非常实用,使find命令对搜索结果中的文件执行指定的shell命令,其中command表示shell命令,大括号{}表示搜索结果中的文件名,最后的分号表示命令的结束,分号需要使用反斜线转义。注意其中的空格。
find ./ -type f -mmin +5 -exec rm {} \;
#找出当前目录下最后一次在5分钟以前修改过的文件并删除。
2.find命令的应用场景
(1) 使用find查找文件中包含指定字符串hello world的txt或者sh文件
find ./ -type f -name "*.sh" -o -name "*.txt" -exec grep -i "hello world" {} \+;
# 注意{}两端的空格。
# “+”号的作用:可以打印出详细结果,包括匹配文件名和匹配行内容
# or:逻辑或,在命令中用“-o”表示。本例中表示sh文件或者txt文件都满足测试条件。
# and:逻辑与,系统默认选项,测试条件之间以空格隔开即可。
# not :逻辑非,在命令中用“!”表示,例如:
find ./ ! -name "*.sh"
那么能不能使用管道来实现呢?例如下面这样:
find ./ -type f -name "*.sh" -o -name "*.txt" | grep -i "hello world"
#不能得到结果。
这样无法想要的结果,因为管道会把find的结果作为输入赋给grep命令,这些结果只是文件名组成的字符串而不是文件的内容。
(2) 搭配xargs解决参数列太长导致溢出的错误
参考资料:Xargs用法详解
在使用find命令的-exec选项处理匹配到的文件时,find命令将所有匹配到的文件一起传递给exec执行。但有些系统对能够传递给exec的命令长度有限制,这样在find命令运行几分钟之后,就会出现 溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。
可以把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部,不像-exec选项那样。这样它可以先处理最先获取的一部分文件,然后是下一批,并如此继续下去。
在使用xargs命令时,究竟是一次获取所有的参数,还是分批取得参数,以及每一次获取参数的数目都会根据该命令的选项及系统内核中相应的可调参数来确定。
并且,xargs可以把管道传来的字符串当作文件去执行,这样就解决了(1)中的问题。
find ./ -type f -name "*.sh" -o -name "*.txt" | xargs grep -i "hello world"
xargs就是为了能对find搜索到的文件进行操作而编写的,还有很多其他的用途,例如:
find . -perm -7 -print | xargs chmod o-w
#在当前目录下查找所有用户具有读、写和执行权限的文件,并收回相应的写权限。
find / -name *.jpg -type f -print | xargs tar -cvzf images.tar.gz
#查找所有的jpg 文件,并且压缩它。
find ~ -name ‘*.log’ -print0 | xargs -i -0 rm -f {}
#尝试用rm删除太多的文件,你可能得到一个错误信息:/bin/rm Argument list too long。用xargs去避免这个问题。
ls *.jpg | xargs -n1 -i cp {} /external-hard-drive/directory
#拷贝所有的图片文件到一个外部的硬盘驱动。
(3) 统计目录中全部的文件数量及子目录数量。
例如以下的shell脚本:
#! /bin/bash
files='find /etc -type f -print | wc -l'
#统计文件数量
directories='find /etc -type d -print | wc -l'
#统计子目录数量
echo "There are $files regular files in /etc dictionary."
echo "There are $directinories directinories in /etc dictionary."
#输出统计结果
(4) 设置crontab任务。
工作里很多task都要在服务器上进行,很难清晰的记录到每一个自己所生成修改的文件,其中的权限问题可能会对其他人产生一些困扰。我们可以设置crontab任务,定时的修改自己文件所属的组或者文件的权限来控制此问题。例如:
00 05 * * * find /path -user tyroneli -mtime -1 -exec chgrp groupid {} \;
#在每天5点,在path目录下查找最后修改时间一天之内用户名为tyroneli的文件或目录,修改其所属组。