File Searching

locate:通过名字查找文件

1
locate [OPTION]... [PATTERN]...

locate程序会快速地搜索其内部的路径名数据库,然后输出每个绝对路径中包含了[PATTERN]的文件的绝对路径。[PATTERN]一般为普通的字符串,但有些版本还会包括正则表达式匹配和通配符匹配。

1
2
3
4
5
6
7
[meme@localhost Playground]# locate bin/zip
/usr/bin/zip
/usr/bin/zipcloak
/usr/bin/zipgrep
/usr/bin/zipinfo
/usr/bin/zipnote
/usr/bin/zipsplit

locate的路径名数据库由updatedb程序创建。该程序会在特定的时间间隔(如每次开机)被守护进程cron执行,因此一些新创建的文件可能无法用locate进行搜索,但是我们也可以以超级用户的身份手动运行updatedb

1
[root@localhost Playground]# updatedb

find:在目录层次结构中搜索文件

1
find [path...] [expression]

locate可以让我们简单地用文件名找到文件的位置,而find则可以让我们在指定的目录[path](绝对或相对路径)下,用文件的各种属性匹配相应的文件。在了解find之前,我们先在当前目录下创建100个子目录,并在每个子目录下创建24个普通文件:

1
2
3
4
5
6
7
8
[meme@localhost Playground]$ mkdir dir-{00{1..9},0{10..99},100}
[meme@localhost Playground]$ ls
dir-001 ... dir-100
[meme@localhost Playground]$ touch dir-{00{1..9},0{10..99},100}/file-{A..Z}
[meme@localhost Playground]$ ls dir-001
file-A ... file-Z
[meme@localhost Playground]$ ls dir-002
file-A ... file-Z

在最基本的用法里,find会输出所查目录及其子目录的所有文件的路径,其中,相对路径查找输出相对路径,绝对路径查找则输出绝对路径:

1
2
3
4
5
6
7
8
[meme@localhost Playground]$ find ./dir-001
./dir-001
...
./dir-001/file-Z
[meme@localhost Playground]$ find /home/meme/Playground/dir-001
/home/meme/Playground/dir-001
...
/home/meme/Playground/dir-001/file-Z

Tests:测试条件

find拥有众多的测试条件,每个测试条件都一定程度上对应着文件的一项属性。find在指定目录中遍历文件元数据时,会使用用户指定的测试条件来筛选文件。

-type

-type选择文件的类别:b块设备文件、c字符设备文件、d目录、f普通文件、l符号链接:

1
2
3
4
5
6
[meme@localhost Playground]$ find ./dir-001 -type f
./dir-001/file-A
...
./dir-001/file-Z
[meme@localhost Playground]$ find ./dir-001 -type d
./dir-001

-name

-name选择文件的名字。此处的名字只是名字,而不包含路径:

1
2
[meme@localhost Playground]$ find ./dir-001 -name '*1'
./dir-001

-size

-size选择文件的大小,后面跟着的字符串,+1M表示只选择大于1M的文件,-1M表示只选择小于1M的文件,1M表示只选择大小等于1M的文件:

1
2
3
4
5
6
[meme@localhost Playground]$ find ./dir-001 -size '1M'
./dir-001
[meme@localhost Playground]$ find ./dir-001 -size '-1M'
./dir-001/file-A
...
./dir-001/file-Z

其他

除了上面这三个常用的测试条件,find还支持很多其他的测试条件,如-perm mode选择指定权限mode的文件等。

Operators:操作符

find的测试条件实际上相当于程序语言中的条件语句,因此,它很自然地也能支持各种条件语句的逻辑组合。这些组合与编程语言中的一样,通过逻辑操作符-and-or-not来实现。这些逻辑操作符的运算逻辑和执行特性和一般程序语言中的没有任何区别。通常地,逻辑操作符连接的两个测试条件应该分别用()括起来。在命令行中,()有特殊的意义,因此实际上要为()加上转义字符,即实际应使用\(\)

  • -andfind的默认操作符,即若测试条件之间没有操作符,那么其连接符号默认是-and
    1
    2
    3
    4
    [meme@localhost Playground]$ find . -type f -name '*A'
    ./dir-001/file-A
    ...
    ./dir-100/file-A
    1
    2
    3
    4
    [meme@localhost Playground]$ find . \( -type f \) -and \( -name '*A' \)
    ./dir-001/file-A
    ...
    ./dir-100/file-A
    上面两个命令是等价的。
  • -or:表,用法与-and相同。
  • -not:表,用在想要取的测试条件之前。
    1
    2
    [meme@localhost Playground]$ find ./dir-001 -not -type f
    ./dir-001

Actions:行为

find允许用户对筛选结果立即进行操作,即,将筛选结果作为其他命令的输入参数。

  • -delete:删除当前匹配到的文件;
  • -ls:对当前匹配到的文件执行ls操作;
  • -print:将当前匹配文件的路径打印出来,是find的默认操作;
  • -quit:一旦找到一个匹配项就退出。

以上四个是find内部自带的操作,如-delete

1
2
[meme@localhost Playground]$ find ./dir-001 -type f -delete
[meme@localhost Playground]$ ls ./dir-001

需要注意的是,TestsActionsfind看来是同优先级的,而find又是顺序过滤的,因此不同的TestsActions的顺序很重要。

用户自定义行为

除了find自带的这几种行为,find还允许用户自由地使用所有合法的Linux命令,一般的格式为:

1
-exec [command] '{}' ';'

因为{};在命令行中有特殊意义,所以必须被引用为字符串或者转义。

如,对筛选出来的文件使用rm -r操作:

1
2
3
4
5
6
7
8
[meme@localhost Playground]$ find . -name '*1'
./dir-001
...
./dir-091
[meme@localhost Playground]$ find . -name '*1' -exec rm -r '{}' ';'
find: './dir-001': No such file or directory
...
find: './dir-091': No such file or directory

有时为了安全起见,我们会想要一个个地确认Actions的效果,此时我们可以使用-ok来代替-exec。使用-ok后,[command]在执行前会先向用户进行确认:

1
2
3
4
5
6
7
8
[meme@localhost Playground]$ find . -name '*2' -ok rm -r '{}' ';'
< rm ... ./dir-002 > ? n
< rm ... ./dir-012 > ? n
< rm ... ./dir-022 > ? n
< rm ... ./dir-032 > ? y
find: './dir-032': No such file or directory
< rm ... ./dir-042 > ? n
...

当我们使用';'时,我们在告诉find:对于每一个匹配的文件,运行一次[command],这样会导致当匹配结果有$n$个文件时,[command]被运行$n$次。要想避免这种情况,我们可以将';'替换为+,这样就是在告诉find:将所有的结果合成一个列表再执行命令:

1
[meme@localhost Playground]$ find . -name '*2' -exec rm -r '{}' +

注意,此时只能用-exec而不能用-ok

辅助命令

有许多的辅助命令能够让locatefind的功能更强大。

xargs

1
xargs [OPTION]... COMMAND INITIAL-ARGS...

xargs从标准输入中接受输入,并将输入转换为一个命令行参数列表,这个参数列表可以直接作为其他指令的参数,如:

1
2
3
4
5
6
7
[meme@localhost Playground]$ find . -name '*13'
./dir-013
[meme@localhost Playground]$ find . -name '*13' | xargs ls -l
total 0
-rw-rw-r--. 1 meme meme 0 Jul 26 19:50 file-A
...
-rw-rw-r--. 1 meme meme 0 Jul 26 19:50 file-Z

xargs./dir-013管道为了ls -l的命令行参数。

touch

1
touch [OPTION]... FILE...

touch后的文件不存在时,touch相当于一个创建文件操作:

1
2
3
4
[meme@localhost Playground]$ locate taylor
[meme@localhost Playground]$ touch taylor
[meme@localhost Playground]$ ls taylor
taylor

若文件已存在,则touch会将其修改时间设置为当前时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
[meme@localhost Playground]$ stat taylor
File: ‘taylor’
...
Access: 2023-07-26 22:32:26.809464671 -0700
Modify: 2023-07-26 22:32:26.809464671 -0700
Change: 2023-07-26 22:32:26.809464671 -0700
[meme@localhost Playground]$ touch taylor
[meme@localhost Playground]$ stat taylor
File: ‘taylor’
...
Access: 2023-07-26 22:33:54.850140719 -0700
Modify: 2023-07-26 22:33:54.850140719 -0700
Change: 2023-07-26 22:33:54.850140719 -0700

stat相当于加强版的ls

参考