跳转至

查找文件

约 1371 个字 129 行代码 1 张图片 预计阅读时间 6 分钟

通配符

通配符不是正则表达式,可直接用于 Linux 中一些系统命令。

常用的通配符:

  • *:0 到多个字符
  • ?:一个字符
  • [字符集]:字符集里的任一字符
  • [a-b]:按字符顺序,字符 a 到字符 b 之间(含两端)的任一字符
  • [^字符集]:上两个的取反关系,即不属于字符集里面的内容的字符

使用通配符时,不能用引号包裹。

查找文件的几种方式

  • which:寻找可执行文件
  • whereis:寻找特定文件
  • locate:搜索文件(按关键字)
  • find:多样化高级查找

which - 寻找可执行文件

which [选项] 命令

只在 PATH 下查找

常用选项:

  • -a:列出 PATH 下所有的该命令文件

例:

# Ubuntu 20.04 LTS
ding@ding-server:~$ which vim
/usr/bin/vim
ding@ding-server:~$ which pwd
/usr/bin/pwd
ding@ding-server:~$ which which
/usr/bin/which
ding@ding-server:~$ which -a echo
/usr/bin/echo
/bin/echo
ding@ding-server:~$ which cd
ding@ding-server:~$
# CentOS Linux release 7.9.2009
ding@ding-server:~$ which vim
/usr/bin/vim
ding@ding-server:~$ which pwd
/usr/bin/pwd
ding@ding-server:~$  which which
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
        /usr/bin/alias
        /usr/bin/which
ding@ding-server:~$ which -a echo
/usr/bin/echo
ding@ding-server:~$ which cd
ding@ding-server:~$

whereis - 寻找特定文件

whereis [选项] 文件名的一部分

PATHMANPATH 中查找。

选项:

  • -b:只查找二进制文件
  • -m:只查找 manual 路径下的文件
  • -s:只查找 source 源文件
  • -u:查找其他文件
  • -l:列出上述条件的查找范围

例:

ding@ding-server:~$ whereis passwd
passwd: /usr/bin/passwd /etc/passwd /usr/share/man/man5/passwd.5.gz /usr/share/man/man1/passwd.1ssl.gz /usr/share/man/man1/passwd.1.gz
ding@ding-server:~$ whereis -b passwd
passwd: /usr/bin/passwd /etc/passwd
ding@ding-server:~$ whereis -m passwd
passwd: /usr/share/man/man5/passwd.5.gz /usr/share/man/man1/passwd.1ssl.gz /usr/share/man/man1/passwd.1.gz
ding@ding-server:~$ whereis -s passwd
passwd:
ding@ding-server:~$ whereis -u passwd
passwd: /usr/bin/passwd /etc/passwd /usr/share/man/man5/passwd.5.gz /usr/share/man/man1/passwd.1ssl.gz /usr/share/man/man1/passwd.1.gz

locate - 搜索文件(按关键字)

locate [选项] 文件名的一部分

Ubuntu 下要安装:

sudo apt install mlocate

基于索引文件查找,故速度较快。

一般每天更新一次索引,如果有新文件可能查不到。强制更新索引:

sudo updatedb

选项:

  • -i:忽略大小写
  • -c:仅显示文件数量
  • -l 数字:仅显示特定条数
  • -r:使用基础正则表达式
  • --regex:使用扩展正则表达式
  • -S:输出索引文件信息(后面不添加文件名的一部分)

例:

ding@ding-server:~$ locate -l 5 vim
/etc/vimrc
/etc/libreport/events.d/vimrc_event.conf
/etc/profile.d/vim.csh
/etc/profile.d/vim.sh
/home/foxconn/.vim
ding@ding-server:~$ locate -S
Database /var/lib/mlocate/mlocate.db:
        114,213 directories
        839,650 files
        92,832,925 bytes in file names
        27,867,065 bytes used to store database
ding@ding-server:~$ locate -l 100 -r 'l[a-z]ng\.sh' # 查找名称含有 l*ng.sh 的文件, 其中 * 表示一个小写字母
/etc/profile.d/lang.sh
/usr/lib/rpm/find-lang.sh
ding@ding-server:~$ locate -l 100 --regex 'l[a-z]+ng\.sh'   # 查找名称含有 l*ng.sh 的文件, 其中 * 表示至少一个小写字母
/etc/profile.d/lang.sh
/home/foxconn/python3/Python-3.9.5/Doc/library/multiprocessing.shared_memory.rst
/usr/lib/rpm/find-lang.sh

find - 多样化高级查找

find [路径] [选项] [操作]

遍历目录查找,速度较慢,但能够查到新文件。

如果访问时出错会报错,影响观感,可将其重定向掉。

路径为要查找的文件所在的路径,多个路径用空格隔开。

与时间相关的选项

以下 n 均为数字,mtime 的情况也可以用在 atimectime 上,time 可以换为 min 表分钟。

  • -mtime n:在“n 天之前的一天之内”被修改过内容的文件
  • -mtime +n:在“n 天之前(不含 n 天本身)”被修改过内容的文件
  • -mtime -n:在“n 天之内(含 n 天本身)”被修改过内容的文件
  • -newer 文件:列出比给定文件新的文件

与时间相关的选项图解
与时间相关的选项图解

与用户、用户组相关的选项

  • -uid UID:文件所有者 UID 为给定值
  • -gid GID:文件用户组 GID 为给定值
  • -user 用户名:文件所有者为给定用户
  • -group 组名:文件用户组为给定用户组
  • -nouser:文件所有者不在 /etc/passwd
  • -nogroup:文件用户组不在 /etc/group

-nouser-nogroup 出现的情况:

  • 对应用户、用户组被删除
  • 文件来源为其他地方,且保留了属性

与文件相关的选项

  • -name 文件名:文件名为给定值,可使用通配符
  • -iname 文件名:同上,但不区分大小写
  • -size [+-]SIZE:文件大小比 SIZE 大 / 小

    • SIZE 的格式如:50k200c;单位对应:
    b(默认) c w k M G
    512B 的块 B 双字节文本 KiB MiB GiB
  • -type 类型:文件类型为给定类型:

b c d p f l s
块设备 字符设备 目录 管道 普通文件 符号链接 套接字

与权限相关的选项

以下数字包含三位和四位的情况。

  • -perm 数字:权限为给定数字
  • -perm -数字:权限包含给定数字
  • -perm /数字:权限包含给定数字中的任意权限

逻辑运算符

  • -a:且(不写也行)
  • -o:或
  • -not:非

额外可进行的操作

  • -exec 命令:执行命令,通常的格式如下:
    find [路径] [选项] -exec ls -l {} \;
    
    • 其中的命令不可使用别名
  • 每个文件执行一次命令,用 {} 表示查到的文件的路径
  • 最后要有分号并转义
  • -ok 命令:同上,但执行前要输入 y 才执行
  • -print:将结果打印在屏幕上(默认)

列出全部含有 SUID 属性的普通文件,并打印它们的详细文件信息。

ding@ding-server:~$ find / -perm /4000 -type f 2> /dev/null -exec ls -l {} \;
-r-Sr--r-- 1 root docker 16696 May 23 14:43 /home/foxconn/p/test
-rwsr-xr-x 1 root root 22840 Feb 21 20:58 /usr/lib/policykit-1/polkit-agent-helper-1
-rwsr-xr-x 1 root root 473576 Mar 30 21:03 /usr/lib/openssh/ssh-keysign
-rwsr-xr-x 1 root root 14488 Jul  8  2019 /usr/lib/eject/dmcrypt-get-device
-rwsr-xr-- 1 root messagebus 51344 Apr 29 20:03 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
-rwsr-xr-x 1 root root 53040 Mar 14 16:26 /usr/bin/chsh
-rwsr-xr-x 1 root root 67816 Feb  7 21:33 /usr/bin/su
-rwsr-xr-x 1 root root 85064 Mar 14 16:26 /usr/bin/chfn
-rwsr-xr-x 1 root root 88464 Mar 14 16:26 /usr/bin/gpasswd
-rwsr-xr-x 1 root root 166056 Jan 19  2021 /usr/bin/sudo
-rwsr-sr-x 1 daemon daemon 55560 Nov 13  2018 /usr/bin/at
-rwsr-xr-x 1 root root 31032 Feb 21 20:58 /usr/bin/pkexec
-rwsr-xr-x 1 root root 39144 Mar  7  2020 /usr/bin/fusermount
-rwsr-xr-x 1 root root 68208 Mar 14 16:26 /usr/bin/passwd
-rwsr-xr-x 1 root root 55528 Feb  7 21:33 /usr/bin/mount
-rwsr-xr-x 1 root root 39144 Feb  7 21:33 /usr/bin/umount
-rwsr-xr-x 1 root root 44784 Mar 14 16:26 /usr/bin/newgrp

练习

1

查找家目录下的所有扩展名为 sh 的文件,并统计它们的第一行书写形式的数量(只统计第一行以 #! 开头的)。

参考答案
1
2
3
4
5
ding@ding-server:~$ find ~ -name '*.sh' 2> /dev/null -exec head -1 {} \; \
> | grep '^#!' | sort | uniq -c
     22 #!/bin/bash
     22 #!/bin/sh
      9 #!/usr/bin/env bash
如果考虑家目录下面有自己访问不了的文件:
1
2
3
4
5
ding@ding-server:~$ cd ~; sudo find ./ -name '*.sh' -exec head -1 {} \; \
> | grep '^#!' | sort | uniq -c
     23 #!/bin/bash
     22 #!/bin/sh
      9 #!/usr/bin/env bash
!!! info 在 `cd ~; sudo find ./` 处,我尝试过传入用户名,前面加上 `~`,但不行;故先用自己进入家目录,后面 `find` 用 `./`
其他方法(来自一位同事,稍加修改)
1
2
3
4
5
ding@ding-server:~$ cd ~; sudo find ./ -type f -name *.sh -exec head -n 1 {} \; | grep -E "^#!" \
> | awk '{S[$1]++} END {for (a in S) {print a, S[a]}}'
#!/bin/sh 22
#!/bin/bash 23
#!/usr/bin/env 9
上述过程中数据的变化:
// 假如 grep -E "^#!" 之后
#!/bin/bash
#!/usr/bin/env bash
#!/bin/sh
#!/usr/bin/env bash
#!/bin/bash

// awk '{S[$1]++}' 的实质
S[#!/bin/bash] ++
S[#!/usr/bin/env bash] ++
S[#!/bin/sh] ++
S[#!/usr/bin/env bash] ++
S[#!/bin/bash] ++

// awk '{S[$1]++}' 之后
S[#!/bin/bash] == 1
S[#!/usr/bin/env bash] == 1
S[#!/bin/sh] == 1
S[#!/usr/bin/env bash] == 2
S[#!/bin/bash] == 2

2

查找 /usr/bin 下的符号链接文件,并列出它们的源文件的详细信息。

不需要再找链接的链接。记得去重。

提示:ls -d 目录:对目录,只显示目录的信息,而非目录下的文件的信息。

参考答案 这种操作最好先分步执行,查看输出结果,根据结果设计下一步;最后组合。
ding@ding-server:~$ cd /usr/bin; sudo find /usr/bin -type l -exec ls -l {} \; \
> | awk '{print $NF}' | sort -u | xargs -n 1 ls -ld
drwxr-xr-x 2 root root 36864 May 25 16:18 .
-rwxr-xr-x 1 root root 7415 Oct 26  2021 add-apt-repository
-rwxr-xr-x 1 root root 2558 Dec  5  2019 apport-bug
-rwsr-sr-x 1 daemon daemon 55560 Nov 13  2018 at
-rwxr-xr-x 1 root root 1183448 Apr 18 17:14 bash
-rwxr-xr-x 1 root root 819296 Feb 15  2020 btrfs
-rwxr-xr-x 1 root root 2172376 Nov 25  2021 busybox
-rwxr-xr-x 1 root root 8363 Feb 17  2020 byobu
-rwxr-xr-x 1 root root 389 Dec 17  2019 chardetect3
-rwxr-xr-x 1 root root 963 Feb 17  2020 col1
lrwxrwxrwx 1 root root 22 Mar 10 01:57 cpp-9 -> x86_64-linux-gnu-cpp-9
-rwxr-xr-x 1 root root 129816 Jul 19  2019 dash
...
!!! info 在 `cd /usr/bin;` 处:经测试可以发现,链接指向的很多都是相对路径,考虑到最后面的 `ls`,故先进入该目录

总结

解决问题的方式不止一种,不过最好能够找到最佳的方式。

参考资料