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标志之后使用directory或d* :
$ 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标志来匹配多个扩展名。例如,要搜索扩展名为sh或txt*的文件:
$ 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在当前目录中搜索。要在某些特定目录中执行搜索,我们可以在模式后指定多个路径参数。
我们可以搜索目录one和two中的所有文件:
$ fd . ./one ./two -t f
one/test-File.sh
one/test-File.txt
two/test-File.sh
two/test-File.txt
此示例中包含三个组件:
- 我们使用单个点作为匹配任何内容所需的文件模式。
- ./one和*./two*是我们正在搜索的路径。
- -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命令还提供了对输出格式的更多控制。