Linux 下搜索文件

通配符

通配符(wildcard)是 Bash 操作接口的一个功能。常用的通配符如下表:

符号 意义
* 代表 0 到无穷多个任意字符。
? 代表一定有一个任意字符。
[] 代表一定有一个括号内的字符,例如 [xgw] 代表可能是 xgw 其中一个。
[-] 代表在编码顺序内的所有字符,例如 [0-9] 代表 0 到 9 之间的所有数字。
[^] 第一个字符为 ^ 代表反向选择,例如 [^xpw]代表任意一个非 xpw 的字符。

快速搜索

在 Linux 中,可以使用不同的命令进行快速搜索,以下是一些常用命令。

使用 which 命令来查找命令所在路径。这个命令根据的是$PATH 环境变量所指定的路径去查询:

[root@101c7 ~]$ which ls
alias ls='ls --color=auto'
        /usr/bin/ls

whereis 命令会在指定的几个常用目录中搜索文件,使用 -l 参数可以查看可搜索的目录。

whereis 命令可以搜索以下类型的文件:二进制文件(-b)、说明文件(-m)、源代码(-s)和其他特殊文件(-u)。

例如搜索和 ifconfig 有关的说明文档:

[root@101c7 audit]$ whereis -m ifconfig
ifconfig: /usr/share/man/man8/ifconfig.8.gz

locate 命令使用数据库来查找文件。数据库存放在 /var/lib/mlocate/ 目录下,每天会更新一次。若需要手动更新数据库,可以使用 updatedb 命令。

例如忽略大小写搜索与 passwd 有关的文件,并列出前四个结果:

[root@101c7 audit]$ locate -i -l 4 passwd
/etc/passwd
/etc/passwd-
/etc/pam.d/passwd
/etc/security/opasswd

精确搜索

精确搜索指使用find命令执行的搜索。

按时间搜索文件

与时间有关的参数有-atime-ctime-mtime

参数 说明
-mtime n 表示在 n 天之前那天内被更改过的文件;
-mtime +n 列出在 n 天之前(不含 n)被更改过的文件,文件修改日期大于等于 n+1 天;
-mtime -n 列出在 n 天之内(包含 n)被更改过的文件,文件修改日期小于等于 n 天;
-newer file 列出比file还要新的文件名。

例如,搜索过去系统上 24 小时内有更改过的文件:

[root@101c7 ~]$ find / -mtime 0
/dev/char
/dev/char/189:132

查找当前目录下修改时间在 5 分钟到 24 小时之间的文件:

[root@101c7 ~]$ find -mtime 0 -mmin +5
.
./.bash_history
./audit

寻找/etc目录下比/etc/passwd文件日期新的文件:

[root@101c7 ~]$ find /etc -newer /etc/passwd | tail 
/etc/audit/audit.rules
/etc/postfix
/etc/kernel

查找/root目录下更改时间在 5 天前的文件并删除:

[root@101c7 audit]$ find /root -type f -mtime +5 -ok rm{} \;

删除当前目录中访问时间在 7 天以前,含有数字后缀的admin.log文件:

[root@101c7 ~]$ find . -name "admin.log[0-9][0-9][0-9]" -atime -7 -exec rm {} \;

按用户名及组名搜索

可以使用 find 命令按照文件的所有者和用户组来搜索文件,常用参数如下:

参数 说明
-uid n 按照用户 UID 来搜索
-gid n 按用户组 GID 来搜索
-user name 按用户名来搜索
-group name 按用户组名来搜索
-nouser 搜索文件的所有者不存在 /etc/passwd 的人
-nogroup 搜索所有用户组不存在 /etc/group 中的文件

例如查找 /home 目录下属于用户 abc 的文件:

[root@101c7 ~]$ find /home -user abc

查找系统中不属于任何人的文件:

[root@101c7 ~]$ find / -nouser

按文件名及属性搜索

主要参数:

参数 说明
-name filename 搜索文件名为 filename 的文件
-iname filename 忽略大小写,搜索文件名为 filename 的文件
-size [±]SIZE 搜索大小比 SIZE 大(+)或小(-)的文件,大小单位有 c、k、m、g 等
-type TYPE 搜索文件类型为 TYPE 的文件,如一般文件(f)、设备文件(b、c)、目录(d)、连接(l)、socket(s)等
-perm mode 搜索权限刚好等于 mode 的文件,如 mode 为 4775
-perm -mode 搜索权限必须全部包括 mode 的权限,如 mode 为 0744,会找到权限为 4775 的文件
-perm +mode 搜索权限包含任一 mode 的权限,如 mode 为 755 时,会找到权限为 101 的文件

例如,在当前目录中查找文件 redis-3.2.6.tar.gz 并删除:

[root@101c7 audit]$ find -name redis-3.2.6.tar.gz -delete

忽略大小写,在 /etc 目录下搜索 ssh 文件或目录:

[root@101c7 audit]$ find /etc -iname ssh
/etc/ssh
/etc/selinux/targeted/active/modules/100/ssh

/etc 目录中查找以 rc 开头的文件,并以列表形式显示:

[root@101c7 audit]$ find /etc -name rc* -ls
50332831    0 drwxr-xr-x  10 root     root          127 Sep  7 05:53 /etc/rc.d
16781412    0 drwxr-xr-x   2 root     root           45 Oct 13  2020 /etc/rc.d/rc0.d
33644238    0 drwxr-xr-x   2 root     root           45 Oct 13  2020 /etc/rc.d/rc1.d
50332832    0 drwxr-xr-x   2 root     root           45 Oct 13  2020 /etc/rc.d/rc2.d

/root 目录下搜索所有小于 1MB 的文件,用 -size -1M 参数等同于 -size 0M,需要注意。这是个 ChatGPT 都会答错的问题:

[root@101c7 audit]$ find /root -size -1M
/root/audit/a.log
/root/3/3

查找 /root 目录下大于 10KB 并且(-a 表示“与”)小于 2M 的普通文件,并以列表形式显示:

[root@101c7 ~]$ find /root -type f -size +10k -a -size -2M -exec ls -lh {} \;
-rw-------. 1 root root 17K Sep 16 03:15 /root/.bash_history
-rw-------. 1 root root 178K Sep  9 05:48 /root/audit/b.log
-rw-r--r--. 1 root root 30K Sep 10 15:05 /root/backup/sdb4.dump
-rw-r--r--. 1 root root 11K Sep 10 14:39 /root/backup/lost.dump.bz2

查找当前目录中的所有目录并排序:

[root@101c7 ~]$ find . -type d | sort
.
./3
./audit

在当前目录下查找除普通文件以外的所有类型的文件:

[root@101c7 ~]$ find . ! -type f -print
.
./.pki
./.pki/nssdb

查找 /bin/sbin 目录下中含有 SGID, SUID 或 SBIT 属性的文件:

[root@101c7 ~]$ find /bin /sbin -perm +7000

处理搜索结果

find 命令可以接受表达式,表达式可能由下列成份组成:操作符、选项、测试表达式以及动作。

常见动作有 -print(打印输出,默认动作)、-ls(显示长目录列表)、-delete(删除文件)。

-exec 选项后面跟命令(不支持别名)或脚本,然后是大括号 {} 表示由 find 找到的路径名,一个空格,接 \ 用来转义分号;表示命令结束。相应命令的形式为 command {} \

-ok-exec 的作用相同,只不过在执行每一个命令之前都会给出提示,让用户来确定是否执行。

例如在 /etc 目录中搜索 passwd 文件并从中找 root 相关信息:

[root@101c7 audit]$ find /etc -name "passwd*" -exec grep "root" {} \;
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

/usr/sam 目录下查找不在 dir1 子目录之内的所有文件:

[root@101c7 ~]$ find /usr/sam -path "/usr/sam/dir1" -prune -o -print

复制搜索到的文件到 backup 目录下:

[root@101c7 ~]$ find . -type f -exec cp --parents  {} ./backup/ \;

-exec 为每个文件生成一条单独的命令,例如搜索到 57 个文件,那么将生成 57 条单独命令。如果想要提高效率,可以使用 xargs 运行任何使用参数指定的命令,参数通过标准输入传递给程序。

例如配合 grepfind 找到的文件中搜寻特定内容:

[root@server1 ~]$ find /var -name *.log | xargs grep "notice"
/var/log/anaconda/X.log:        (++) from command line, (!!) notice, (II) informational,
/var/log/anaconda/journal.log:Sep 22 13:09:41 localhost kernel: type=1107 audit(1632316181.830:44): pid=1577 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc:  received policyload notice (seqno=2)

将搜索到的文件重命名,可以在 xargs 中使用 {} 占位符来代表搜索结果:

[root@server1 ~]$ find . -name "back.sh*" | xargs -i mv {} {}.dele
[root@server1 ~]$ ll back*
-rwxr--r--. 1 root root 52 Oct  7 06:15 back.sh1.dele
-rwxr--r--. 2 root root 52 Sep 23 19:18 back.sh.dele