Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

2.17. find - search for files in a directory hierarchy

2.17.1. 多目录匹配

{/System,}/Library/Fonts

匹配 /System/Library/Fonts 和 /Library/Fonts 两个目录

		
find {/System,}/Library/Fonts -name \*ttf
		
		

2.17.2. name

Find every file under directory /usr ending in "stat".

$ find /usr -name *stat
/usr/src/linux-headers-2.6.24-22-generic/include/config/cpu/freq/stat
/usr/bin/lnstat
/usr/bin/sar.sysstat
/usr/bin/mpstat
/usr/bin/rtstat
/usr/bin/nstat
/usr/bin/lpstat
/usr/bin/ctstat
/usr/bin/stat
/usr/bin/kpsestat
/usr/bin/pidstat
/usr/bin/iostat
/usr/bin/vmstat
/usr/lib/sysstat
/usr/share/doc/sysstat
/usr/share/gnome/help/battstat
/usr/share/omf/battstat
/usr/share/zsh/help/stat
/usr/share/zsh/4.3.4/functions/Completion/Unix/_diffstat
/usr/share/zsh/4.3.4/functions/Completion/Zsh/_stat
/usr/share/zsh/4.3.4/functions/Zftp/zfstat
		
find  \( -iname '*.jpg' -o -iname '*.png' -o -iname '*.gif'  \)

find /www/images -type f \( -iname '*.js' -o -iname '*.css' -o -iname '*.html' \) | xargs tar -czf ~/images.tgz
		

使用通配符

find . -name "*.jsp" -delete
find . -name "*.xml" -delete
		

2.17.3. regex

find . -regex ".*\.\(jpg\|png\)"
		

下面regex与name作用相同

find . -regex ".*\.\(txt\|sh\)"
find . -name "*.sh" -o -name "*.txt"
		

-regex参数,使用正则表达式来匹配. 查找当前目录以及子目录中以 ".sh",并改为以".shell"结尾.

		
[neo@netkiller test]# tree a
a
├── a.py
├── a.sh
└── b
    ├── b.py
    ├── b.sh
    ├── c
    │   └── c.sh
    └── d
        └── d.sh

[neo@netkiller test]# find ./a -type f  -regex ".*\.sh$" | sed -r -n 's#(.*\.)sh$#mv & \1shell#e'
[neo@netkiller test]# tree a
a
├── a.py
├── a.shell
└── b
    ├── b.py
    ├── b.shell
    ├── c
    │   └── c.shell
    └── d
        └── d.shell

 // 注意 sed s->e  使用方式,官方文档是这样解释的.
This command allows one to pipe input from a shell command into pattern space. If a substitution was made, the command that is found in pattern space is executed and pattern space is replaced with its output. A trailing newline is suppressed; results are undefined if the command to be executed contains a NUL character. This is a GNU sed extension.
		
		

2.17.4. user

Find every file under /home and /var/www owned by the user neo.

$ find /home -user neo
$ find /var/www -user neo
$ find . -user nobody -iname '*.php'
		

2.17.5. perm

find ./ -perm -7 -print | xargs chmod o-w
find . -perm -o=w
		

查找当前目录下权限为777的文件并显示到标准输出

find ./ -type f -perm 777 -print
		

2.17.6. type

分别设置文件与目录的权限
find /usr/www/phpmyadmin -type d -exec chmod 755 {} \;
find /usr/www/phpmyadmin -type f -exec chmod 644 {} \;
			

2.17.7. -delete

# find /var/spool/clientmqueue/ -type f -delete
		

保留最近7天的问题,其他全部删除

find . -type f -mtime +7 -delete
		
			
find . -type f -name "*.xhtml" -delete
			
		

2.17.8. exec

替换文本

# find ./ -exec grep str1 ‘{}’ \; -exec sed -i.bak s/str1/str2/g ‘{}’ \;
		
find -exec ls -l {} \; | grep '2011-01-18'
		

查找*.html文件中aaa替换为bbb

find . -name "*.html" -type f -exec sed -i "s/aaa/bbb/" {} \;
		

查找文件中含有openWindow字符串的文件

# find -type f -name "*.js" -exec grep -H -A2 openWindow {} \;

./javascript/commonjs.js:function openWindow(url){
./javascript/commonjs.js-	window.open(url + "?rand=" + getRandom(), 'gamebinary');
./javascript/commonjs.js-}
		
find -type f -regex ".*\.\(css\|js\)" -exec yuicompressor {} -o {} \;
find -type f -name "*.js" -exec yuicompressor --type js {} -o {} \;
find -type f -name "*.css" -exec yuicompressor --type css {} -o {} \;
		

2.17.9. 排除目录

find /usr/local -path "/usr/local/share" -prune -o -print

find /usr/local \( -path /usr/local/bin -o -path /usr/local/sbin \) -prune -o -print

find /usr/local \(-path /usr/local/dir1 -o -path /usr/local/file1 \) -prune -o -name "temp" -print
		

查找当前目录下的php文件,排除子目录templates_c, caches

find . \( -path ./templates_c -o -path ./caches \) -prune -o -name "*.php" -print
		

2.17.10. -ctime / -cmin - 按状态改变时间查找

ctime (change time) 表示文件状态最后一次被改变的时间。当文件的元数据(metadata)发生变化时,ctime 会更新,包括:

  • 文件权限变更(chmod)

  • 文件所有者变更(chown)

  • 文件链接数变化

  • 文件重命名或移动

  • 文件内容修改(mtime 改变时 ctime 也会同时更新)

ctime 与 mtime、atime 的区别:

  • mtime - 文件内容修改时间

  • atime - 文件最后访问时间

  • ctime - 文件状态(元数据)改变时间,不可人为修改

时间参数的含义:

  • -n - 最近 n 天内状态改变的文件

  • +n - n 天前状态改变的文件

  • n - 恰好第 n 天状态改变的文件

-ctime 基本用法

查找最近 7 天内状态改变的文件:

find . -type f -ctime -7
			

查找 30 天前状态改变的文件:

find . -type f -ctime +30
			

查找恰好第 1 天状态改变的文件:

find . -type f -ctime 1
			
-cmin 按分钟查找

查找最近 60 分钟内状态改变的文件:

find . -type f -cmin -60
			

查找 5 分钟前状态改变的文件:

find . -type f -cmin +5
			
常见使用场景

查找最近权限被修改的文件:

find /etc -type f -ctime -1 -ls
			

查找并删除 6 天前的空目录:

find ./ -type d -empty -ctime +6 -exec rm -rf {} \;
			

查找 7 天前状态改变的备份文件并删除:

find /backup/svn/day -type f -ctime +7 -exec rm -f {} \;
find /backup/svn/day -type f -ctime +7 -delete
find /backup/svn/day -type f -ctime +7 | xargs rm -f
			

查找最近 24 小时内所有者变更的文件:

find /home -type f -ctime -1 -ls
			
ctime 的特殊性

ctime 的一个重要特性是:当文件内容被修改时,mtime 和 ctime 会同时更新。例如:

# 创建一个测试文件
$ touch testfile
$ stat testfile
Access: 2026-08-05 10:00:00.000000000 +0800
Modify: 2026-08-05 10:00:00.000000000 +0800  # mtime
Change: 2026-08-05 10:00:00.000000000 +0800  # ctime

# 修改文件内容
$ echo "test" > testfile
$ stat testfile
Access: 2026-08-05 10:00:00.000000000 +0800
Modify: 2026-08-05 10:05:00.000000000 +0800  # mtime 更新
Change: 2026-08-05 10:05:00.000000000 +0800  # ctime 也更新

# 仅修改权限
$ chmod 755 testfile
$ stat testfile
Access: 2026-08-05 10:00:00.000000000 +0800
Modify: 2026-08-05 10:05:00.000000000 +0800  # mtime 不变
Change: 2026-08-05 10:10:00.000000000 +0800  # ctime 更新
			

2.17.11. -mtime / -mmin - 按修改时间查找

mtime (modification time) 表示文件内容最后一次被修改的时间。当文件的数据被写入时,mtime 会更新。

find 命令支持三种时间类型:

  • -mtime - 文件内容修改时间 (modification time)

  • -atime - 文件访问时间 (access time)

  • -ctime - 文件状态改变时间 (change time,包括权限、所有者等元数据变更)

时间参数的含义:

  • -n - 最近 n 天(24小时为单位)内修改的文件

  • +n - n 天前修改的文件(超过 n*24 小时)

  • n - 恰好第 n 天修改的文件(在 n*24 到 (n+1)*24 小时之间)

-mtime 基本用法

查找最近 3 天内修改的文件:

find . -type f -mtime -3
			

查找 3 天前修改的文件:

find . -type f -mtime +3
			

查找恰好第 7 天修改的文件:

find . -type f -mtime 7
			
-mmin 按分钟查找

与 -mtime 类似,但以分钟为单位:

# 查找最近 30 分钟内修改的文件
find . -type f -mmin -30

# 查找 60 分钟前修改的文件
find . -type f -mmin +60

# 查找恰好 15 分钟前修改的文件
find . -type f -mmin 15
			
结合 -exec 执行操作

删除 30 天前的日志文件:

find /var/log -type f -name "*.log" -mtime +30 -exec rm -f {} \;
			

压缩 7 天前的大文件:

find /data -type f -size +100M -mtime +7 -exec gzip {} \;
			

修改 1 天前的文件权限:

find /tmp -type f -mtime +1 -exec chmod 600 {} \;
			
结合 xargs 批量处理

删除 90 天前的临时文件(性能更好):

find /tmp -type f -mtime +90 | xargs rm -f
			

统计最近 1 天内修改的文件数量:

find /home -type f -mtime -1 | xargs wc -l | tail -1
			
实际应用场景

例 2.1. 增量备份(find + tar)

# 备份最近 7 天修改的文件
find / -type f -mtime -7 | xargs tar -rf weekly_incremental.tar
gzip weekly_incremental.tar
				

例 2.2. 清理过期日志

# 保留 7 天,删除更早的日志文件
COPIES=7
find /var/log -type f -name "*.log" -mtime +$COPIES -delete
				

例 2.3. 查找并移动旧文件

# 将 30 天前的文件移动到归档目录
find /data -type f -mtime +30 -exec mv {} /archive/ \;
				

例 2.4. 按时间和大小组合查找

# 查找 7 天前且大于 10MB 的文件
find /var/log -type f -mtime +7 -size +10M -ls
				

查看文件时间戳

使用 stat 命令查看文件的详细时间信息:

$ stat filename
  File: filename
  Size: 1234      	Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 1234567     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/   user)   Gid: ( 1000/   user)
Access: 2026-08-05 10:30:00.000000000 +0800  # atime - 访问时间
Modify: 2026-08-04 15:20:00.000000000 +0800  # mtime - 修改时间
Change: 2026-08-04 15:20:00.000000000 +0800  # ctime - 状态改变时间
			
	# find . -mmin +5 -mmin -10
			
	find /www -type f -mtime +60s
			

2.17.12. --newer

tar --newer="2011-07-04" -zcvf backup.tar.gz /var/www/
tar cvzf foo.tgz /bak -N "2004-03-03 16:49:17"
		

2.17.13. -print / -printf

[root@scientific ~]# find / -maxdepth 1 -name '[!.]*' -printf 'Name: %16f Size: %6s\n'
Name:                / Size:   4096
Name:             misc Size:      0
Name:            media Size:   4096
Name:             home Size:   4096
Name:              dev Size:   3840
Name:              net Size:      0
Name:             proc Size:      0
Name:             sbin Size:  12288
Name:             root Size:   4096
Name:              lib Size:   4096
Name:           cgroup Size:   4096
Name:              srv Size:   4096
Name:              mnt Size:   4096
Name:              etc Size:  12288
Name:              usr Size:   4096
Name:            lib64 Size:  12288
Name:             boot Size:   1024
Name:              var Size:   4096
Name:          selinux Size:      0
Name:              opt Size:   4096
Name:              tmp Size:   4096
Name:       lost+found Size:  16384
Name:              sys Size:      0
Name:              bin Size:   4096

# find /etc/ -type f -printf "%CY-%Cm-%Cd %Cr %8s %f\n"
		

2.17.14. -size

查找0字节文件

find /www -type f -size 0
		

查找根目录下大于1G的文件

find /  -type f -size +1000M
		

2.17.15. -path

搜索当前目录下除了keys目录下所以子目录中的文件

find ./ -path "./keys" -prune -o -type f -print
		

find排除多个目录

find ./ \( -path ./conf -o -path ./logs \) -prune -o -print

find /data/ \( -path /data/data_backup -o -path /data/mysql \) -prune -o -name "core.*" -type f
/data/mysql
/data/data_backup
		

ps 要么都是绝对路径 要么都是相对路径 /data/ 必须有"/" path 后面的路径必须没有"/"

包含 */target/* 目录

		
[gitlab-runner@localhost cloud.netkiller.cn]$ find . -type f -name "*.jar" -path "*/target/*"
		
		

排除 lib 目录

		
[gitlab-runner@localhost cloud.netkiller.cn]$ find . -type f -name "*.jar" ! -path "lib"
		
		

		
[gitlab-runner@localhost cloud.netkiller.cn]$ find . \( ! -path "*/zito-common/*" -a ! -path "./lib/*" \) -type f -name "*.jar"
		
		

2.17.16. 目录深度控制

		
neo@MacBook-Pro ~/workspace/Linux % find */images -type d -d 0 -exec echo {} \;
Cryptography/images
Monitoring/images
OpenLDAP/images
Project/images
Web/images
		
		
		
find */images -type d -d 0 -exec rsync -au {}/* $(PUBLIC_HTML)/linux/images \;
		
		
-maxdepth

-maxdepth和-mindepth,最大深度,最小深度搜索,搜索当前目录下最大深度为1的所以文件

find . -maxdepth 1 -type f
		

2.17.17. xargs

find /etc -type f|xargs md5sum
		

sha1sum

find /etc -type f|xargs sha1sum
		
find ./ -name "*html" | xargs -n 1 sed -i -e 's/aaa/bbb/g'
		
find /tmp -name core -type f -print | xargs /bin/rm -f
find . -type f -exec file '{}' \;
		

find后执行xargs提示xargs: argument line too long解决方法:

find . -type f -name "*.log" -print0 | xargs -0 rm -f
		

-i 参数可以使用 {}

		
[gitlab-runner@localhost cloud.sfzito.com]$ find . \( ! -path "*/zito-common/*" -a ! -path "./lib/*" -a ! -path "./dist/*" \) -type f -name "*.jar" | xargs -i cp {} dist/
		
		

2.17.18. 查看空文件

		
find . -type f -name "*.txt" -empty
		
		

删除空文件

		
find . -type f -name "*.txt" -empty -delete