// 安全研究 · 2025-08-18

【新手易混】find -exec -perm 等选项用法

1. 引言

在 Linux 系统中,find 可能是命令行工具中最“有深度”的一个——多数用户只知道它按名称搜索文件,但在安全审计、系统维护、批量处理等场景下,-perm(权限匹配)与 -exec(批量执行)的组合才是其真正的威力所在。

本文将从一个具体的安全排查场景切入,完整拆解 find -exec 的语法陷阱、-perm 的高级用法,以及如何将这些能力串联成实战中的高效工作流。

核心问题:当你想找出系统中所有设置了 SUID 权限位的文件,并对它们执行某些批量操作(如移动、修改权限、记录日志)时,你的命令行能不能做到准确、安全、可解释?

2. -perm:权限匹配的三种模式

-perm 选项用于按文件权限进行筛选,其行为由前导符号决定。

2.1 模式速查表

模式 示例 匹配逻辑
精确匹配 -perm 644 权限必须完全等于 644
包含匹配 -perm -4000 所有指定权限位都设置(可有多余位)
任意匹配 -perm /4000 任意一个指定权限位被设置

2.2 精确匹配(无符号):-perm 644

含义:文件权限必须严格等于 644(rw-r--r--)。

# 查找权限完全等于 644 的文件
find / -type f -perm 644

# 查找权限完全等于 755 的目录
find / -type d -perm 755

这种模式很少单独使用,因为匹配条件过于苛刻——文件权限稍有不同(如因 umask 生成 600)就会被排除。

2.3 包含匹配(- 前缀):-perm -4000

这是权限检查的“超集”模式:文件中指定的所有权限位都必须在。

# 查找所有设置了 SUID(4000)的文件(权限可额外有 755)
find / -type f -perm -4000

# 查找同时设置了 SUID 和 SGID 的文件(4000+2000=6000)
find / -type f -perm -6000

# 查找所有用户都能写的文件(002 模式:其他用户有写权限)
find / -type f -perm -0002

实用技巧:查找所有人都能写的敏感文件:

find /etc -type f -perm -0002 -exec ls -l {} \;
# 等价写法:匹配 -o+w 或 -g+w
find /etc -type f -perm -002 -o -perm -020

2.4 任意匹配(/ 前缀):-perm /4000

含义:只要文件的权限中包含任意一个指定权限位,就匹配。

# 查找设置了 SUID 或 SGID 的文件
find / -type f -perm /6000

# 查找任何用户有执行权限的文件(不安全)
find / -type f -perm /0111

# 查找可被任何用户读的文件(隐私泄露风险)
find /home -type f -perm /0004 -ls

2.5 符号模式:-perm -u=s

GNU find 还支持符号权限模式,比八进制更易读:

符号 含义 等价八进制
-perm -u=s 设置了 SUID -4000
-perm -g=s 设置了 SGID -2000
-perm -o=t 设置了 sticky bit -1000
-perm -g=w 组用户有写权限 -020
-perm -o=w 其他用户有写权限 -002
-perm -a+x 所有用户有执行权限 -0111
# 符号模式示例
find / -type f -perm -u=s -ls              # SUID 文件
find / -type f -perm -u=s -o -perm -g=s    # SUID 或 SGID
find /tmp -type d -perm -o=t               # 粘滞位目录

3. -exec:批量操作的“发动机”

-exec 将 find 从“查找工具”升级为“批量处理引擎”。其语法结构需要精确遵守。

3.1 基础语法

find [路径] [条件] -exec [命令] {} [后缀]
符号 含义
{} 匹配到的文件路径占位符
\; 命令结束符(每个文件执行一次)
\+ 命令结束符(所有文件一次执行)

3.2 单文件执行(\;)

每找到一个文件就执行一次命令。适用于需要对每个文件独立处理的操作(如 chmod)。

# 每个文件单独执行一次 chmod
find . -type f -name "*.conf" -exec chmod 644 {} \;

# 每个文件单独统计行数
find . -type f -name "*.py" -exec wc -l {} \;

3.3 批处理执行(\+)

将所有匹配到的文件路径拼接成一行参数,一次性执行命令。效率远高于逐文件执行。

# 一次 chmod 处理所有文件
find . -type f -name "*.conf" -exec chmod 644 {} \+

# 合并所有 .txt 文件到一个文件中
find . -type f -name "*.txt" -exec cat {} \+ > all.txt

3.4 -execdir 与 -ok

替代命令 行为差异
-execdir 在文件所在目录执行命令,更安全(路径不含 ./)
-ok 执行前询问确认,适合危险操作
# 危险操作前确认
find /tmp -type f -name "*.tmp" -ok rm {} \;

# 使用 -execdir 避免路径问题
find ~/project -type f -name "*.md" -execdir rename 's/\.md/.txt/' {} \;

4. 实战案例:安全审计与系统维护

4.1 场景一:排查 SUID/SGID 风险文件

需求:找出所有设置了 SUID 或 SGID 位的文件,并导出清单到文件。

find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -la {} \; > /tmp/suid_sgid_report.txt

拆解:

  • -perm -4000:SUID 位
  • -perm -2000:SGID 位
  • \( ... -o ... \):组条件,表示“或”
  • -exec ls -la:以长格式显示文件详情
  • > 重定向到报告文件

4.2 场景二:查找全局可写文件

需求:找出系统中所有其他用户可写的文件,并立即收紧权限到 644。

find / -type f -perm -0002 -exec chmod 644 {} \;

若担心误操作,先用 -ok 确认:

find / -type f -perm -0002 -ok chmod 644 {} \;

4.3 场景三:大批量文件重命名

需求:将当前目录下所有 .jpeg 文件重命名为 .jpg。

find . -type f -name "*.jpeg" -exec bash -c 'mv "$0" "${0%.jpeg}.jpg"' {} \;

4.4 场景四:压缩超过 30 天的日志

需求:将 /var/log 下超过 30 天未修改的 .log 文件压缩归档。

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

4.5 场景五:批量生成文件哈希

find ~/downloads -type f \( -name "*.exe" -o -name "*.iso" \) -exec sha256sum {} \; > checksums.txt

5. 安全陷阱与性能优化

5.1 -exec 的特殊字符问题

问题:{} 作为参数时,如果文件名包含空格或特殊字符,可能导致命令解析错误。

解决方案:结合 -print0 与 xargs -0:

find . -type f -name "*.txt" -print0 | xargs -0 -I {} mv {} {}.bak

find -exec vs xargs 对比:

特性 find -exec find + xargs
特殊字符安全 需 -print0 + xargs -0 -print0 + xargs -0
并行处理 ❌ 不支持 xargs -P N
语法复杂度 低(一行完成) 中(需理解管道)
单次执行开销 低(内置) 需启动外部 xargs

5.2 跨文件系统搜索的边界

find 默认会跨越挂载点(如 /proc、/sys),可能导致异常输出或性能问题。

# 限制在当前文件系统(-xdev)
find / -xdev -type f -perm -4000

5.3 -exec 执行效率对比

场景 推荐方式 原因
处理少量文件 -exec {} \; 语法简单,开销可接受
处理大量文件 -exec {} + 大幅减少进程启动次数
需要并行处理 -print0 | xargs -0 -P 多核利用
操作不可逆 -ok 逐条确认,防止误删

6. -perm 模式拓展

6.1 基于八进制模式的权限筛选

# 查找权限为 755 的目录
find /var/www -type d -perm 755

# 查找至少具有 755 权限的目录(多了 777 也匹配)
find /var/www -type d -perm -755

6.2 组合权限条件

# 查找 SUID 但非 root 拥有的文件(异常 SUID)
find / -type f -perm -4000 ! -user root -ls

# 查找全局可写但不可执行的脚本
find /home -type f -perm -0002 ! -perm -0111 -name "*.sh"

6.3 条件嵌套

# 查找最近 7 天内修改且权限过于宽松的配置文件
find /etc -type f -name "*.conf" -mtime -7 \( -perm -002 -o -perm -020 \)

7. 总结:find 组合技的本质

find 的高级用法(-perm + -exec)本质上是一个声明式的命令行编程语言:

组件 作用 类比
搜索路径 数据源 SQL 中的 FROM
测试条件 过滤逻辑 SQL 中的 WHERE
-exec 对结果集执行操作 SQL 中的 SELECT 或 UPDATE
-o / -a 布尔组合 SQL 中的 OR / AND

三条核心原则:

  1. 精确匹配用八进制,模糊匹配用符号或 -// 前缀

    • -perm 644:必须完全匹配
    • -perm -644:至少具有这些权限(可包含更多)
    • -perm /644:任一位匹配即可
  2. 批处理优于逐条处理,\+ 优于 \;

    • 处理大量文件时,\+ 减少进程创建开销
    • 每条命令的性质决定能否批处理(如 chmod 可以,mv 不行)
  3. 先过滤,后执行,用 -ok 保护危险操作

    • 先用 -printf 或 -ls 预览匹配结果
    • 确认无误后再将 -ok 替换为 -exec

掌握这些组合,find 将成为你解决批量文件问题的核心发动机——无论是安全审计、日志清理还是代码重构,都能用清晰、紧凑、可复用的命令行表达完整意图。

原文 https://blog.csdn.net/2301_79518550/article/details/150487349