find 命令用于在指定目录下查找文件和目录。它可以使用不同的选项来过滤和限制查找的结果。
语法:find [paths] [expression] [actions]
参数说明:
path:要查找的目录路径,可以是一个目录或文件名,也可以是多个路径,多个路径之间用空格分隔,如果未指定路径,则默认为当前目录。
expression:可选参数,用于指定查找的条件,可以是文件名、文件类型、文件大小等等。
动作:可选的,用于对匹配到的文件执行操作,比如删除、复制等。
find常用参数
- -name pattern :搜索时使用 pattern 对文件名进行匹配
- -type t :根据文件类型搜索,可以是 f(普通文件)、d(目录)、l(符号链接)、p(管道文件)、b(块设备文件)、c(字符设备文件)
- -path pattern :搜索时使用 pattern 对文件路径进行匹配
- -size [+-]n[ckMGTP] :根据文件大小搜索:支持使用 + 或 - 表示大于或小于指定大小,单位可以是 c(字节)、w(字数)、b(块数)、k(KB)、M(MB)或 G(GB)
- -user uname :按文件所有者查找,支持使用通配符
*
和?
- -group gname :按文件所属组查找
- -uid userID :按照用户 ID 査找所有者是指定 ID 的文件
- -gid groupID :按照用户组 ID 査找所属组是指定 ID 的文件
- -perm mode :根据文件权限搜索
- -delete :删除检索到的文件
- -ls :打印搜索到的文件的详细信息
- -empty :检索空文件或空目录
- -exec :对搜索到的结果执行特定的命令,命令形式为:"command {} \;" 因为分号是 Shell 中有特殊含义的符号,所以需要转义(\)或需要使用单引号括起来
- -ok :和 -exec 作用相同,但以一种更加安全的方式来执行命令,在执行每条命令之前都会给出提示,让用户来确定是否要执行
- -amin [+-]n:查找在 n 分钟内被访问过的文件,支持使用 + 或 - 表示在指定时间前或后
- -cmin [+-]n :查找在 n 分钟内状态发生变化的文件(例如权限),支持使用 + 或 - 表示在指定时间前或后
- -mmin [+-]n :查找在 n 分钟内被修改过的文件,支持使用 + 或 - 表示在指定时间前或后
- -atime [+-]n :查找在 n*24 小时内被访问过的文件,支持使用 + 或 - 表示在指定时间前或后
- -ctime [+-]n :查找在 n*24 小时内状态发生变化的文件(例如权限),支持使用 + 或 - 表示在指定时间前或后
- -mtime [+-]n :查找在 n*24 小时内被修改过的文件,支持使用 + 或 - 表示在指定时间前或后
- -newer file1 ! file2:查找更改时间比文件file1 新但比文件file2旧的文件。
- -iname pattern :同 -name,忽略大小写
- -ipath pattern :同 -path,忽略大小写
- -depth n :检索深度为 n 的文件,即位于指定目录以下 n 层的文件
- -maxdepth n :指定递归的最大层数为 n,默认不限制深度
- -mindepth n :指定递归的最小层数为 n,默认不限制深度
- -nouser:查找没有有效所有者的文件
- -nogroup:查找没有有效所属组的文件
- -fstype type :指定文件所在的文件系统的类型
- -not:取反操作,排除满足条件的文件或目录
- -and:与操作,同时满足多个条件
- -or:或操作,满足任意一个条件即可
- -fprint filename:将匹配的文件输出到文件。
- -print: 将匹配到的文件输出到标准输出
- -print0: 将匹配到的文件输出到标准输出,且输出的文件列表以 null(\0) 分隔
- -follow:如果find命里遇到符号链接文件,就跟踪至连接所指向的文件。
根据时间日期进行检索
Linux 系统中,与文件相关联的时间参数有以下三种:
- 修改时间(Modification time):最后一次文件内容有过更改的时间点
- 访问时间(Access time):最后一次文件有被读取过的时间点
- 变更时间(Change time):最后一次文件有被变更过的时间点(如内容被修改,或权限等 metadata 被修改)
与此对应的是 find 命令中的:
- -amin, -cmin, -mmin:单位是分钟
- -atime, -ctime, -mtime:单位是天
“-amin n"和”-atime n"的处理方法都是:根据当前时间和文件的相应时间属性求差值,然后比较差值和参数n,看是否符合要求。但是这个求差值的过程却有很大不同,他们的不同也代表了两组(基于分钟和基于天)的不同:
"-amin n"
(1)求Δt,用当前时间减去文件时间值即得到Δt,Δt = tnow - tfile;
(2)求浮点数f,用Δt除以1分钟,f = Δt / 1min;
(3)将f的小数部分入到整数部分,得到差。即,不管f是6.0102还是6.8901,差值都等于7
"-atime n"
(1)求Δt,用当前时间减去文件时间值即得到Δt,Δt = tnow - tfile;
(2)求浮点数f,用Δt处以24小时,f = Δt / 24hours;
(3)将f的小数部分都舍掉,得到差。即,不管f是6.0102还是6.8901,差都等于6
-amin +3 +3表示差值大于3
-amin -3 -3表示差值小于3
-amin 3 表示差值等于3
正数应该表示时间之前,负数表示时间之内。
例如:-mtime 0 表示查找今天修改过的文件,-mtime -7 表示查找一周以前修改过的文件。
关于时间 n 参数的说明:
- +n:查找比 n 天前更早的文件或目录。
- -n:查找在 n 天内更改过属性的文件或目录。
- n:查找在 n 天前(指定那一天)更改过属性的文件或目录。
find /usr -type f -mtime +50 -mtime -100
检索 /usr 下 50 到 100 天之前修改过的文件
find /usr -type f -mtime 2 -amin 5
检索 /usr 下两天前被修改过且 5 分钟前又读取过的文件
find . -type f -atime -7
搜索最近七天内被访问过的所有文件
find . -type f -atime 7
搜索恰好在七天前被访问过的所有文件
find . -type f -atime +7
搜索超过七天被访问过的所有文件
find . -type f -amin +10
搜索访问时间超过10分钟的所有文件
-anewer file
-cnewer file
-newer file
find . -type f -newer file.log
找出比file.log内容修改时间更晚的所有文件
根据文件权限检索
使用 -perm 选项以文件权限为依据进行搜索。
使用符号形式
如需要检索 /usr 目录下权限为 rwxr-xr-x 的文件,可以使用以下命令:
find /usr -perm u=rwx,g=rx,o=rx
搜索 /usr 目录下所有权限为 r-xr-xr-x(即系统中的所有用户都只有读写权限)的文件和目录,可以使用以下命令:
find /usr -perm a=rx
很多时候,我们只想匹配文件权限的一个子集。比如,检索可以直接被任何用户执行的文件,即只关心文件的执行权限,而不用管其读写权限是什么。
上述的需求可以通过以下命令实现:
find / -type f -perm /a=x
其中 a=x 前面的 / 符号即用来表示只匹配权限的某个子集(执行权限),而不用关心其他权限的具体设置。
使用数字形式
-perm 选项也支持数字形式的文件权限标记。
- -perm 权限模式:査找文件权限刚好等于"权限模式"的文件
- -perm -权限模式:査找文件权限全部包含"权限模式"的文件
- -perm +权限模式(/权限模式):査找文件权限包含"权限模式"的任意一个权限的文件
搜索 /usr 目录下权限为 644(即 rwxr-xr-x)的文件
find /usr -perm 644
査找文件权限全部包含w的文件
find . -perm -222
査找文件权限包含w的任意一个权限的文件
find . -perm /222
反义匹配
find 命令也允许用户对当前的匹配条件进行“反义”(类似于逻辑非操作),也可以使用 -not 选项。
如需要检索 /usr 下所有文件名不以 .txt 为后缀的文件。可以使用以下命令:
find /usr -type f ! -name '*.txt'
也可以“翻转”任何其他的筛选条件,如:
find /usr -type f ! -empty //检索 /usr 下所有内容不为空的文件
逻辑组合
除取反操作外,find 命令还支持 “and” 和 “or” 两种逻辑运算,对应的命令选项分别是 -a 和 -o。通过这两个选项可以对搜索条件进行更复杂的组合。
此外还可以使用小括号对搜索条件进行分组。注意 find 命令中的小括号常需要用单引号包裹起来。因小括号在 Shell 中有特殊的含义。
如检索 /usr 下文件名以 python 开头且类型为目录的文件:
find /usr -type d -name 'python*'
#该命令等同于:
find /usr -type d -a -name 'python*'
更复杂的组合形式如:
find / '(' -mmin -5 -o -mtime +50 ')' -a -type f
find . -size +2k -a -type f
在当前目录下搜索大于2KB,并且文件类型是普通文件的文件
find . -mtime -3 -a -perm 644
在当前目录下搜索3天以内修改过,并且权限是644的文件
find / -name 'temp' -o -name 'install*'
在根目录下查找文件名为’temp’或是匹配’install*’的所有文件
find ! -name 'Test*'
在当前目录下查找不以Test开头的文件
find . -name "*.txt" -o -print
如果表达式-name "*.txt"为真,就不再执行另一个表达式-print,即查找所有不是以.txt结尾的文件。
find . -name "*e*[0-9]*" ! -type d -print
查找当前目录下,文件名中包括字母'e',在'e'之后又有数字的不是目录文件的所有文件
find . -name "[A-Za-b]*"
当前目录及子目录中查找文件名以一个大写字母开头或者以小写a或b开头的文件
-iname
-name区分大小写,如果不想区分大小写可以使用-iname测试项。
'i'可以加在许多选项前面,比如-ipath,-iregex,-iwholename等等,都是不区分大小写。
执行自定义命令
-exec 选项可以对搜索到的结果执行特定的命令。
如需要将 home 目录下所有的 MP3 音频文件复制到移动存储设备(假设路径是 /media/MyDrive),可使用下面的命令:
find ~ -type f -name '*.mp3' -exec cp {} /media/MyDrive ';'
其中的大括号({})作为检索到的文件的 占位符 ,而分号( ;)作为命令结束的标志。因为分号是 Shell 中有特殊含义的符号,所以需要使用单引号括起来或使用转义符号(\)转义。
每当 find 命令检索到一个符合条件的文件,会使用其完整路径取代命令中的 {},然后执行 -exec 后面的命令一次。
另一个很重要的用法是,在多个文件中检索某个指定的字符串。
如在用户主目录下的所有文件中检索字符串 hello ,可以使用如下命令:
find ~ -type f -exec grep -l hello {} \;
更多例子:
find . EXPR1 -exec command {} \;
注意:后一个花括号'}'和'\'之间有一个空格,最后以分号;结尾,因为各个系统中分号会有不同的意义,所以前面加反斜杠。
{} 花括号代表前面find查找出来的文件名。
find . -type f -exec ls -l {} \;
查找当前目录下的所有普通文件,并用ls命令输出
find .-type f -user root -exec chown tom {} \;
找出当前目录下所有root的文件,并把所有者更改为用户tom
find . -type f -name "*.txt" -exec cat {} \;> all.txt
查找当前目录下所有.txt文件并把他们拼接起来写入到all.txt文件中
find . -type f -mtime +30 -name "*.log" -exec cp {} old \;
将30天前的.log文件移动到old目录中
find . -type f -name "*.txt" -exec printf "File: %s\n" {} \;
找出当前目录下所有.txt文件并以“File:文件名”的形式打印出来
因为单行命令中-exec参数中无法使用多个命令,使用脚本可以实现在-exec之后接受多条命令
-exec ./text.sh {} \;
-exec 选项中的 + 符号
创建 Gzip 格式的压缩文件的命令为:
tar -czvf filename.tar.gz <list of files>
现在假设需要将用户主目录下所有的 MP3 文件添加到压缩包 music.tar.gz 中,直观的感觉是,其命令应为如下形式:
find ~ -type f -name '*.mp3' -exec tar -czvf music.tar.gz {} ';'
实际情况是,这样得到的 music.tar.gz 其实只包含一个 MP3 文件。
原因是 find 命令每次发现一个音频文件,都会再执行一次 -exec 选项后面的压缩命令。导致先前生成的压缩包被覆盖。
可以先让 find 命令检索出所有符合条件的音频文件,再将得到的文件列表传递给后面的压缩命令。完整的命令如下:
find ~ -type f -name '*.mp3' -exec tar -czvf music.tar.gz {} +
排除某个目录
-prune是一个动作项,它表示当文件是一个目录文件时,不进入此目录进行搜索。
-prune经常和-path一起使用,以避开某个目录,常见的形式是:
find PATH -path <dont want> -prune -o -path <want>
find . -path "./sk" -prune -o -name "*.txt" -print
查找当前目录或者子目录下所有.txt文件,但是跳过子目录sk
注意:如果同时使用-depth设置项,那么-prune将被find命令忽略。man手册页中这么说:“If -depth is given, false; no effect.”
实例
//查找当前目录下名为 file.txt 的文件:
find . -name file.txt
//将当前目录及其子目录下所有文件后缀为 .c 的文件列出来:
find . -name "*.c"
//将当前目录及其子目录中的所有文件列出:
find . -type f
//查找 /home 目录下大于 1MB 的文件:
find /home -size +1M
//查找 /var/log 目录下在 7 天前修改过的文件:
find /var/log -mtime +7
//查找过去 7 天内被访问的文件:
find /path/to/search -atime -7
//在当前目录下查找最近 20 天内状态发生改变的文件和目录:
find . -ctime 20
//将当前目录及其子目录下所有 20 天前及更早更新过的文件列出:
find . -ctime +20
//查找 /var/log 目录中更改时间在 7 日以前的普通文件,并在删除之前询问它们:
find /var/log -type f -mtime +7 -ok rm {} \;
//查找当前目录中文件属主具有读、写权限,并且文件所属组的用户和其他用户具有读权限的文件:
find . -type f -perm 644 -exec ls -l {} \;
//查找系统中所有文件长度为 0 的普通文件,并列出它们的完整路径:
find / -type f -size 0 -exec ls -l {} \;
//找并执行操作(例如删除):
find /path/to/search -name "pattern" -exec rm {} \;
//这个例子中,-exec 选项允许你执行一个命令,{} 将会被匹配到的文件名替代,\; 表示命令结束。