find命令在应急中的高效排查技巧
Linux应急响应中,find命令是用的最多的一个命令。分享一些鲜为人知的find命令排查技巧,熟练运用可以达到事半功倍的效果
find使用广度优先遍历查找文件
find命令默认是深度优先遍历,并且不支持广度优先遍历。
应急最头疼的点就在于,需要排查某些文件中的关键字,但是深度优先遍历使得find命令在某些很深的目录中做无用功,而且要搜索完才能进入到下一个一级目录,总是浪费大量时间。
有什么办法使得find支持广度优先遍历呢?
巧妙利用find命令的depth参数
find命令是支持查找目录的层级,比如 -mindepth 和 -maxdepth 参数,分别对应查找最少和最多的目录层级。
seq 1 10 | xargs -n2 -P5 sh -c 'find / -iname "xxx" -mindepth $1 -maxdepth $2 2>/dev/null' _
该命令相当于find查找指定层级的目录,比如第一次是在1-2层目录中查找,第二次在3-4层目录中匹配。上面的命令看起来会有点抽象,换成下面这种就好理解了。
[root@VM-4-7-centos ~]# seq 1 10 | xargs -n2 1 2 3 4 5 6 7 8 9 10 [root@VM-4-7-centos ~]# seq 1 10 | xargs -n2 sh -c 'echo find / -iname xxx -mindepth $1 -maxdepth $2 2>/dev/null' _ find / -iname xxx -mindepth 1 -maxdepth 2 find / -iname xxx -mindepth 3 -maxdepth 4 find / -iname xxx -mindepth 5 -maxdepth 6 find / -iname xxx -mindepth 7 -maxdepth 8 find / -iname xxx -mindepth 9 -maxdepth 10
xargs -P5 的是指 5个子进程同时执行,可提升查找速度。
seq 1 10 表示最多查找10层目录,可根据自身需要修改。
配合grep查找文件内关键字
seq 1 10 | xargs -n2 -P5 sh -c 'find / -type f -mindepth $1 -maxdepth $2 -exec grep -inl "keyword" {} 2>/dev/null \;' _
匹配成功后不会直接匹配的内容,而是打印文件的路径。对于不清楚特定关键字位于哪个文件时,该命令排查非常高效。
find查找指定时间段内变动的文件
这也是我在排查中用的最多的一个选项。有时需要定位某一个时间段内的文件变动就需要用到 -newermt 选项。格式如下:
find / -newermt “开始时间” ! -newermt “截止时间”
注意中间的感叹号不能省略。
比如我要查找 2022年12月31日23:00 到 2023年1月1日1:00 期间发生变动的文件,条件看起来比较苛刻,但 -newermt 可以完全满足。命令如下:
find / -newermt "2022-12-31 23:00" ! -newermt "2023-01-01 01:00" 2>/dev/null
或者还可以输出文件的修改时间。
find / -newermt "2022-12-31 23:00" ! -newermt "2023-01-01 01:00" -exec ls -lh {} \; 2>/dev/null
查找过去n天的文件变动
比如查找过去3天内的文件变动,命令如下:
find / -type f -mtime -3
如果先查找3天前的文件变动则是:
find / -type f -mtime +3
find查找特定权限的文件
查找可执行文件
find /root -executable -type f -exec ls -lh {} \; -quit
- -executable 指定可执行权限的文件
- -quit 匹配到第一个符合条件的文件就退出
查找带s位的文件
find / \( -perm -4000 -o -perm -2000 \) -type f -exec ls -lh {} \; 2>/dev/null
-perm -4000
表示包含setuid
位的文件-perm -2000
表示包含setgid
位的文件- -o 表示或的关系
为什么是-perm -4000 而不是-perm 4000,有何区别?
在 find
命令中使用 -perm
选项时,-
前缀有特殊的含义。-perm -mode
会匹配任何文件的权限中设置了任何 mode
指定的位的文件,而 perm mode
只会匹配文件权限完全等于 mode
的文件。
例如,-perm -4000
会匹配所有设置了 setuid 位的文件(不考虑其他权限位是什么),而 -perm 4000
会匹配文件权限完全为 4000
(即只有 setuid 位被设置,其他所有权限位都没有被设置)的文件。
查找指定权限的文件
比如要查找系统中0700权限的文件,这里和上面的例子恰好相反,是完全匹配。
find / -perm 0700 -type f -exec ls -lh {} \; 2>/dev/null
find 目录取反
应急排查中,往往需要排除掉部分指定的目录。比如查找根目录下的所有可执行文件,但排除/usr目录。
find / -path /usr -prune -o -type f -executable
在这个命令中,-path /usr -prune -o
表示如果路径是 /usr
,则不搜索该路径,否则继续执行后面的命令。
如果要排除多个目录呢?
find / \( -path /usr -o -path /etc \) -prune -o -executable
这时候就需要括号把多个目录放在一起进行过滤。
find 并行操作
以使用 +
代替 \;
来在 find
命令中执行并行操作。
比如排查完成之后需要把一些不同层级目录下的文件,统一打包回传。例如把 /targetDir 下面所有的可执行进行打包并压缩。
find /targetDir -type f -executable -exec tar -rvf executables.tar {} + gzip executables.tar
或者首先找到所有的文件,然后一次性将它们添加到 tar 存档中。这样你就可以将存档压缩,而无需追加文件。注意-print0
和 -0
选项是用来处理文件名中可能包含的特殊字符(如空格或换行符)的。
find . -type f -executable -print0 | xargs -0 tar -czvf executables.tgz
但这种方式没有用到find的并行。
再举一个例子,要在一个目录中查找所有 .jpg
文件并将它们复制到另一个目录,命令如下
:
find /path/to/dir -name "*.jpg" -exec cp {} /path/to/other/dir +
这将使用尽可能多的参数来调用 cp
,而不是每找到一个文件就调用一次 cp
。
find中 exec 的 + 和 \; 的区别?
在 find
命令的 -exec
操作后面,可以用 \;
或 +
结束。
- 当使用 \
;
结束时,对每个匹配到的文件,find
命令都会执行一次-exec
后面指定的命令。如果找到了100个文件,那么命令就会执行100次。 - 当使用
+
结束时,find
命令会尽可能多地将匹配的文件名作为参数一次性传递给-exec
后面指定的命令,这样命令可能只执行一次。
+
的方式通常更为高效,因为它减少了需要执行的命令的次数。然而,并非所有的命令都能接受多个文件作为参数,对于这种情况就需要使用 \;
的方式。
find 正则表达式搜索
-regex
选项可以使用正则表达式进行搜索,而不仅仅是简单的文件名匹配。例如要查找png或者jpg结尾的文件。
find / -regex ".*\.\(jpg\|png\)$"
会同时找到所有的 .jpg
和 .png
文件,满足更复杂的查找需求。
如何解决文件名存在空格导致的报错?
比如查找文件的前10行是否包含@字符,如果文件名中包含空格,使用下面命令会出现报错。
find ./ -maxdepth 1 -name "*.txt" -exec sh -c 'head -10 $1 | grep -qF "@" && ls -lh $1 ' _ {} \;
正确的写法是文件名占位符加上双引号。
find ./ -maxdepth 1 -name "*.txt" -exec sh -c 'head -10 "$1" | grep -qF "@" && ls -lh "$1" ' _ {} \;
如何在-exec sh -c ‘command’ 中嵌套使用单引号?
例如想在-exec 中嵌套使用sed这里必须用到单引号的场景
sed -i 's/\t/ /g' inputfile
可以这样写。
find . -name "*.txt" -exec sh -c 'sed -i '\''s/\t/ /g'\'' {}' \;
在每个单引号之前再加上一个 ‘\’
赞赏微信赞赏支付宝赞赏
发表评论