Contents

Linux find命令的替代方案fd命令

1. 概述

在使用 Linux 时,我们经常想从终端搜索文件。

内置的find命令广泛用于此目的。但是,还有一个替代命令 - fd - 它具有一些附加功能,包括更友好的彩色输出、更快的搜索速度和一些有用的默认值。

在本教程中,我们将了解如何使用fd

2. 安装

fd实用程序在几乎所有软件包存储库中都可用。我们可以在 OpenSUSE、Fedora 或 Manjaro 中安装fd包。在 Ubuntu 19.04 及更新版本中,我们可以安装fd-find包:

$ sudo apt install fd-find

虽然在 Ubuntu 中命令名称是fdfind ,但我们可以设置一个别名:

$ alias fd=fdfind

3. 创建测试文件

对于我们的示例,让我们在临时目录中快速创建一些文件:

$ mkdir -p /tmp/blogdemo-fd/one /tmp/blogdemo-fd/two
$ cd /tmp/blogdemo-fd/
$ touch one/test-File.txt two/test-File.txt
$ echo '#!/bin/sh\n:' | tee one/.hiddenFile.sh one/test-File.sh two/.hiddenFile.sh two/test-File.sh
$ chmod +x one/test-File.sh

在这一步之后,我们有一些普通的文本文件、隐藏文件和 shell 脚本。我们使用tee命令将echo命令的输出保存到所有四个文件中。

我们还将当前工作目录设置为*/tmp/blogdemo-fd*。

让我们用tree命令查看目录结构:

$ tree -a
.
├── one
│   ├── .hiddenFile.sh
│   ├── test-File.sh
│   └── test-File.txt
└── two
    ├── .hiddenFile.sh
    ├── test-File.sh
    └── test-File.txt
2 directories, 6 files

4. 基本用法

无需额外参数,我们可以运行fd来查看当前目录的内容:

$ fd
one
one/test-File.sh
one/test-File.txt
two
two/test-File.sh
two/test-File.txt

**我们可以看到,fd默认不显示隐藏文件。**如果我们的终端支持,这个输出也会被着色。

fd的力量来自我们应用的过滤器。当我们添加过滤器时,我们还可以提供一个 path 参数来告诉fd在那个路径中搜索,而不是在当前目录中搜索。

让我们看看如何过滤。

4.1. 常用表达

默认情况下,fd将搜索模式视为正则表达式并执行不区分大小写的搜索

$ fd 'file[.]sh'
one/test-File.sh
two/test-File.sh

在这里,我们的 file[.]sh表达式正在寻找任何包含 不区分大小写的file.sh的文件。

由于点字符是正则表达式通配符,我们将其括在方括号 [] 中以引用它。但是,我们可以使用不带引号的点字符来匹配特定目录中的任何文件:

$ fd . two
two/test-File.sh
two/test-File.txt

由于我们只能在指定模式的情况下指定路径,因此点 (.) 是一种有用的全匹配模式。

4.2. 通配符匹配

如果我们希望使用像星号 (*) 这样的通配符,就像我们在其他 shell 命令中可能使用的那样,而不是正则表达式,那么-g*标志可以通过通配符启用文件通配符或匹配*:

$ fd 'test-*.sh' -g
one/test-File.sh
two/test-File.sh

4.3. 简单字符串匹配

有时我们需要匹配一个包含正则表达式特殊字符的字符串。虽然我们可以引用它们,但使用***-F*标志更容易指示参数应该按原样匹配**:

$ fd -F 'file.sh'
one/test-File.sh
two/test-File.sh

这个简单的字符串匹配通过将模式匹配为子字符串来工作。

4.4. 区分大小写的搜索

我们可以使用-s*标志启用区分大小写。*

因此,虽然默认搜索 文件会找到结果:

$ fd file ./one
one/test-File.sh
one/test-File.txt

打开标志后,它不再匹配:

$ fd -s file ./one
# no match

此外,如果模式包含大写字符,则会自动启用区分大小写的模式:

$ fd filE ./one
# no match

4.5. 显示隐藏文件

fd默认忽略隐藏文件。我们可以使用-H*标志在搜索结果中包含隐藏文件*:

$ fd -H file ./two
two/.hiddenFile.sh
two/test-File.sh
two/test-File.txt

5. 指定搜索条件

5.1. 按文件类型搜索

*我们可以使用-t*标志和文件类型指示符来搜索文件类型。**一些常见的文件类型指示器:

  • f, file – 常规文件
  • d、目录——目录
  • l、symlink——符号链接
  • x,可执行文件——可执行文件
  • e、empty – 空文件或目录

让我们尝试列出所有子目录。在这里,我们可以在*-t标志之后使用directoryd* :

$ fd -t directory
one
two

我们可以重复*-t标志来组合几个文件类型标准。要查找所有空文件,我们可以使用-t*标志两次。

$ fd -t e -t f
one/test-File.txt
two/test-File.txt

在此示例中,带参数e的第一个*-t标志匹配空文件或目录。带有参数f的第二个-t*标志匹配常规文件。该组合为我们提供了空的常规文件列表。

5.2. 按文件扩展名搜索

*我们还可以使用-e标志来搜索具有特定扩展名的文件。**要查找以扩展名sh*结尾的文件:

$ fd -e sh
one/test-File.sh 
two/test-File.sh

我们也可以重复*-e标志来匹配多个扩展名。例如,要搜索扩展名为shtxt*的文件:

$ fd -e sh -e txt
one/test-File.sh
one/test-File.txt
two/test-File.sh
two/test-File.txt

5.3. 匹配完整路径

默认情况下,搜索模式只匹配文件或目录的名称。使用-p*标志,模式与完整路径匹配*:

让我们在*/tmp*目录中搜索其完整路径与给定正则表达式匹配的所有文件:

$ fd -p 'blogdemo.*sh' /tmp 
/tmp/blogdemo-fd/one/test-File.sh 
/tmp/blogdemo-fd/two/test-File.sh

正如我们所见,正则表达式匹配文件的绝对路径。我们应该注意这仍然是一个子字符串匹配,尽管我们可以添加正则表达式锚*^$*来强制匹配分别包括路径的开始或结束。

5.4. 在多个位置搜索

默认情况下,fd在当前目录中搜索。要在某些特定目录中执行搜索,我们可以在模式后指定多个路径参数。

我们可以搜索目录onetwo中的所有文件:

$ fd . ./one ./two -t f 
one/test-File.sh 
one/test-File.txt 
two/test-File.sh 
two/test-File.txt

此示例中包含三个组件:

  1. 我们使用单个点作为匹配任何内容所需的文件模式。
  2. ./one和*./two*是我们正在搜索的路径。
  3. -tf匹配常规文件并从结果中省略目录。

6. 高级用法

6.1. 遍历符号链接

默认情况下,fd不遵循符号链接。我们可以使用-L*标志遍历符号链接。*

首先,让我们使用ln 命令创建名为one的子目录的符号链接:

$ ln -s one symone

现在让我们搜索一个可执行文件:

$ fd -t x
one/test-File.sh

正如我们所见,它没有显示新创建的符号链接的内容。让我们使用*-L*标志包含符号链接的内容:

$ fd -t x -L
one/test-File.sh
symone/test-File.sh

现在我们也有了符号链接的内容。

有时我们希望在遵循符号链接时避免遍历另一个文件系统。我们可以通过使用–one-file-system*标志来防止进入另一个文件系统。*

6.2. 控制目录遍历深度

我们还可以使用标志*-d、–min-depth–exact-depth*来控制目录遍历深度。让我们创建几个目录,一个在另一个:

$ mkdir -p ./two/sub/moresub

此命令搜索所有文件和目录,但最大深度限制为 2:

$ fd -d 2
one 
one/test-File.sh 
one/test-File.txt 
symone 
two 
two/sub 
two/test-File.sh 
two/test-File.txt

相反,我们可以指定查找当前目录下至少 2 级的文件:

$ fd --min-depth 2 
one/test-File.sh 
one/test-File.txt 
two/sub 
two/sub/moresub 
two/test-File.sh 
two/test-File.txt

而且,我们可以在一定深度执行搜索:

$ fd --exact-depth 2 
one/test-File.sh 
one/test-File.txt 
two/sub 
two/test-File.sh 
two/test-File.txt

6.3. 反转搜索结果

有时我们想要反转搜索结果,以便只列出与给定模式不匹配的文件或目录。** -E标志显示与给定 glob 模式不匹配的结果。**我们应该注意,这个标志不支持正则表达式。

例如,通配符模式**.sh匹配扩展名为 sh 的文件。如果我们想搜索任何不以扩展名sh*结尾的文件,我们可以使用以下命令:

$ fd -E '*.sh' -t f
one/test-File.txt
two/test-File.txt

在这里,fd已经返回了所有文件,并从结果中排除了匹配通配符**.sh*的文件。

6.4. 按大小过滤

** -S或*–size标志允许我们指定文件大小限制。**为了理解一个例子,让我们在目录two*中使用dd 命令创建一个 2 KB 的文件:

$ dd if=/dev/random of=./two/largefile count=4 2> /dev/null

要搜索大小为 1 KB 或更大的文件,我们可以使用表达式*+1k* 和*-S*标志:

$ fd -S +1k 
two/largefile

结果是我们刚刚使用dd命令创建的文件,因为它的大小符合我们的标准。

相反,我们可以使用*-1k*来搜索 1 KB 或更小的文件:

$ fd -S -1k
one/test-File.sh
one/test-File.txt
two/test-File.sh
two/test-File.txt

类似地,例如,我们可以使用b表示字节,使用m表示兆字节手册页 上提供了完整的列表。

6.5.按日期过滤

有时我们需要根据创建日期、修改日期或上次访问日期来搜索文件。*我们可以使用–changed-within–changed-before*标志按修改日期过滤。**这两个标志接受时间戳和持续时间作为参数。

我们可以以分钟等单位指定持续时间。我们还可以使用持续时间单位的复数形式:

$ fd -t x --changed-before "2020-09-01 11:00:00"
one/test-File.sh
$ fd -t x --changed-within 2day
one/test-File.sh
$ fd -t x --changed-within 2days
one/test-File.sh

但是,fd不支持按创建日期或上次访问日期进行搜索。

7. 对搜索结果执行命令

有时,我们想要处理文件搜索的结果。我们可以将结果传递给/xargs 以在结果集上运行一些命令。但是,fd允许我们直接调用命令。在执行命令之前扩展以下表达式:

  • {} 小路
  • {.} 没有文件扩展名的路径
  • {/} 基本名称
  • {/.} 没有文件扩展名的基本名称
  • {//} 父目录

7.1. 批量执行

我们可以使用-X*标志对整个结果集仅运行一次命令。* 在这种模式下,fd将搜索结果作为参数列表传递给给定命令。

让我们将结果传递给*file * 命令,该命令在其命令行上输出文件的类型:

$ fd -t f -X file
one/test-File.sh:  POSIX shell script, ASCII text executable 
one/test-File.txt: empty 
two/largefile:     data 
two/test-File.sh:  POSIX shell script, ASCII text executable 
two/test-File.txt: empty

正如我们所看到的,上面的命令等效于以下命令,其中一次传递所有参数:

$ file one/test-File.sh one/test-File.txt two/largefile two/test-File.sh two/test-File.txt

7.2. 重复执行

另一方面,我们可以**使用*-x标志对结果集的每个条目运行命令。*要了解我们如何在结果集的每个条目上运行特定命令,让我们使用-x标志来创建每个文件的备份副本。

例如,让我们告诉fd以指定格式对搜索结果的每个条目调用cp命令:

$ fd -Ht f -x cp {} {}.bak

现在让我们检查是否创建了扩展名为*.bak*的新文件:

$ fd -Ht f -e bak
one/.hiddenFile.sh.bak 
one/test-File.sh.bak 
one/test-File.txt.bak 
two/.hiddenFile.sh.bak 
two/largefile.bak 
two/test-File.sh.bak 
two/test-File.txt.bak

如我们所见,我们通过 使用 -x 标志执行cp创建了备份。

8. 与find比较

根据其 GitHub 页面上的基准测试, fd的运行速度比find命令快得多。与find不同,fd对输出进行着色,忽略隐藏文件,并将输入搜索模式默认视为正则表达式。

另一方面,  fd并不支持find命令的所有功能。某些选项(例如find命令的*-prune标志)不适用于fd*。find命令还提供了对输出格式的更多控制。