4 个稳定版本
10.1.1026 | 2024 年 7 月 17 日 |
---|---|
10.1.1025 | 2024 年 7 月 16 日 |
#304 在 命令行工具
333 每月下载量
200KB
4K SLoC
fd
fd
是一个用于在文件系统中查找条目的程序。它是一个简单、快速且用户友好的 find
的替代品。虽然它并不旨在支持 find
的所有强大功能,但它为大多数用例提供了合理的(有见地的)默认设置。
赞助商
特别感谢我们的主要 赞助商
终端中所有事物的 $HOME。
在 Terminal Trove 中找到您的下一个 CLI / TUI 工具和其他工具。
在我们的通讯中获取新工具的更新。
特性
- 直观的语法:使用
fd 模式
而不是find -iname '*模式*'
。 - 正则表达式(默认)和基于 glob 的模式。
- 非常快,因为并行化目录遍历。
- 使用颜色突出显示不同的文件类型(与
ls
相同)。 - 支持 并行命令执行
- 智能搜索:默认情况下搜索不区分大小写。如果模式中包含大写字母,则会切换到大小写敏感。
- 默认情况下忽略隐藏目录和文件。
- 默认情况下忽略来自您的
.gitignore
的模式。 - 命令名称比
find
短 50%,链接:*。
演示
如何使用
首先,要查看所有可用的命令行选项,您可以通过运行 fd -h
获取简洁的帮助信息,或者运行 fd --help
获取更详细的信息。
简单搜索
fd 是为了在您的文件系统中查找条目而设计的。您可以执行的最基本的搜索是使用单个参数运行 fd:搜索模式。例如,假设您想要找到您的旧脚本(名称包含 netflix
)
> fd netfl
Software/python/imdb-ratings/netflix-details.py
如果只使用一个参数调用,fd 将递归地搜索当前目录以查找包含模式 netfl
的任何条目。
正则表达式搜索
搜索模式被当作正则表达式处理。在这里,我们搜索以 x
开头并以 rc
结尾的条目
> cd /etc
> fd '^x.*rc$'
X11/xinit/xinitrc
X11/xinit/xserverrc
fd
使用的正则表达式语法在此处有说明:*。
指定根目录
如果我们想要搜索特定的目录,我们可以将其作为第二个参数传递给 fd
> fd passwd /etc
/etc/default/passwd
/etc/pam.d/passwd
/etc/passwd
递归列出所有文件
fd 可以不带参数调用。这对于快速查看当前目录中所有条目非常有用,递归地(类似于 ls -R
)
> cd fd/tests
> fd
testenv
testenv/mod.rs
tests.rs
如果您想要使用此功能列出特定目录中的所有文件,您必须使用通配符模式,例如 .
或 ^
> fd . fd/tests/
testenv
testenv/mod.rs
tests.rs
搜索特定文件扩展名
通常,我们对特定类型的所有文件都感兴趣。这可以通过使用 -e
(或 --extension
)选项来完成。在这里,我们搜索 fd 存储库中的所有 Markdown 文件
> cd fd
> fd -e md
CONTRIBUTING.md
README.md
-e
选项可以与搜索模式结合使用
> fd -e rs mod
src/fshelper/mod.rs
src/lscolors/mod.rs
tests/testenv/mod.rs
搜索特定文件名
要找到与提供的搜索模式完全匹配的文件,请使用 -g
(或 --glob
)选项
> fd -g libc.so /usr
/usr/lib32/libc.so
/usr/lib/libc.so
隐藏和忽略的文件
默认情况下,fd 不搜索隐藏目录,并在搜索结果中不显示隐藏文件。要禁用此行为,我们可以使用 -H
(或 --hidden
)选项
> fd pre-commit
> fd -H pre-commit
.git/hooks/pre-commit.sample
如果我们在一个是 Git 仓库(或包含 Git 仓库)的目录中工作,fd 不搜索与 .gitignore
模式匹配的文件夹(也不显示文件)。要禁用此行为,我们可以使用 -I
(或 --no-ignore
)选项
> fd num_cpu
> fd -I num_cpu
target/debug/deps/libnum_cpus-f5ce7ef99006aa05.rlib
要真正搜索 所有 文件和目录,只需组合隐藏和忽略功能以显示所有内容(-HI
)或使用 -u
/--unrestricted
。
匹配完整路径
默认情况下,fd 只匹配每个文件的文件名。但是,使用 --full-path
或 -p
选项,您可以匹配完整路径。
> fd -p -g '**/.git/config'
> fd -p '.*/lesson-\d+/[a-z]+.(jpg|png)'
命令执行
除了显示搜索结果外,您通常还想要对它们进行操作。 fd
提供了两种方式来为您搜索结果的每个结果执行外部命令
-x
/--exec
选项为每个搜索结果运行一个外部命令,它们是 并行 运行的。-
/--exec-batch
选项只运行一次外部命令,所有搜索结果作为 参数。
示例
递归查找所有 zip 归档并将其解压
fd -e zip -x unzip
如果有两个这样的文件,file1.zip
和 backup/file2.zip
,这将执行 unzip file1.zip
和 unzip backup/file2.zip
。这两个 unzip
进程将并行运行(如果文件找到得足够快)。
查找所有 *.h
和 *.cpp
文件,并使用 clang-format -i
在原地自动格式化
fd -e h -e cpp -x clang-format -i
注意,-
选项可以作为一个单独的参数传递给 clang-format
。这就是为什么我们将 -
选项放在最后的原因。
查找所有 test_*.py
文件并在您喜欢的编辑器中打开它们
fd -g 'test_*.py' -X vim
请注意,我们在这里使用大写的 -
来打开单个 vim
实例。如果有两个这样的文件,test_basic.py
和 lib/test_advanced.py
,这将运行 vim test_basic.py lib/test_advanced.py
。
要查看文件权限、所有者、文件大小等信息,您可以通过为每个结果运行 ls
来告诉 fd
显示它们
fd … -X ls -lhd --color=always
此模式非常有用,因此 fd
提供了一个快捷方式。您可以使用 -
/--list-details
选项以这种方式执行 ls
:fd … -
。
当将 fd
与 ripgrep (rg
) 结合使用以在特定类别的文件中搜索时,-
选项也非常有用,例如所有 C++ 源文件
fd -e cpp -e cxx -e h -e hpp -X rg 'std::cout'
将所有 *.jpg
文件转换为 *.png
文件
fd -e jpg -x convert {} {.}.png
这里,{}
是搜索结果的一个占位符。 {.}
与此相同,但没有文件扩展名。有关占位符语法的更多详细信息,请参见下文。
使用-x
从并行线程中运行的命令的终端输出不会交错或混乱,因此可以使用fd -x
来初步并行化在多个文件上运行的任务。一个例子是计算目录中每个单独文件的校验和。
fd -tf -x md5sum > file_checksums.txt
占位符语法
-
和-
选项接受一系列参数(而不是单个字符串)作为命令模板。如果您想在命令模板后添加额外的fd
选项,可以使用\;
来终止它。
生成命令的语法类似于GNU Parallel
{}
:一个占位符,将被搜索结果的路径(例如:documents/images/party.jpg
)替换。{.}
:与{}
类似,但不含文件扩展名(例如:documents/images/party
)。{/}
:一个占位符,将被搜索结果的基名(例如:party.jpg
)替换。{//}
:发现路径的父路径(例如:documents/images
)。{/.}
:不带扩展名的基名(例如:party
)。
如果不包含占位符,fd会自动在末尾添加一个{}
。
并行执行与串行执行
对于-
/--exec
,您可以通过使用-j
/--threads
选项来控制并行作业的数量。使用--threads=1
进行串行执行。
排除特定的文件或目录
有时我们想忽略来自特定子目录的搜索结果。例如,我们可能想搜索所有隐藏的文件和目录(-H
),但排除来自.git
目录的所有匹配项。我们可以使用-E
(或--exclude
)选项来完成此操作。它接受任意glob模式作为参数。
> fd -H -E .git …
我们还可以使用此选项来跳过挂载的目录
> fd -E /mnt/external-drive …
或者跳过某些文件类型
> fd -E '*.bak' …
为了使此类排除模式永久化,您可以创建一个.fdignore
文件。它们像.gitignore
文件一样工作,但仅针对fd
。例如
> cat ~/.fdignore
/mnt/external-drive
*.bak
[!NOTE]
fd
还支持其他程序(如rg或
ag
)使用的.ignore
文件。
如果您想让fd
全局忽略这些模式,可以将它们放入fd
的全局忽略文件中。这通常位于macOS或Linux中的~/.config/fd/ignore
,以及Windows中的%APPDATA%\fd\ignore
。
您可能希望将.git/
包含在您的fd/ignore
文件中,这样在您使用--hidden
选项时,.git
目录及其内容将不会包含在输出中。
删除文件
您可以使用fd
删除所有匹配您搜索模式的文件和目录。如果您只想删除文件,您可以使用--exec-batch/-X
选项来调用rm
。例如,要递归删除所有.DS_Store
文件,请运行
> fd -H '^\.DS_Store$' -tf -X rm
如果您不确定,请首先不带-X rm
调用fd
。或者,使用rm
的“交互式”选项
> fd -H '^\.DS_Store$' -tf -X rm -i
如果您还想删除特定类别的目录,您可以使用相同的技术。您将必须使用rm
的--recursive/-r
标志来删除目录。
[!注意] 在某些情况下,使用
fd … -X rm -r
可能会导致竞态条件:如果您有一个路径如…/foo/bar/foo/…
并且想删除所有名为foo
的目录,您可能会遇到外部的foo
目录首先被删除的情况,导致在rm
调用中出现的无害的"'foo/bar/foo': No such file or directory"错误。
命令行选项
这是fd -h
的输出。要查看完整的命令行选项,请使用fd --help
,它还包括一个更详细的帮助文本。
Usage: fd [OPTIONS] [pattern] [path]...
Arguments:
[pattern] the search pattern (a regular expression, unless '--glob' is used; optional)
[path]... the root directories for the filesystem search (optional)
Options:
-H, --hidden Search hidden files and directories
-I, --no-ignore Do not respect .(git|fd)ignore files
-s, --case-sensitive Case-sensitive search (default: smart case)
-i, --ignore-case Case-insensitive search (default: smart case)
-g, --glob Glob-based search (default: regular expression)
-a, --absolute-path Show absolute instead of relative paths
-l, --list-details Use a long listing format with file metadata
-L, --follow Follow symbolic links
-p, --full-path Search full abs. path (default: filename only)
-d, --max-depth <depth> Set maximum search depth (default: none)
-E, --exclude <pattern> Exclude entries that match the given glob pattern
-t, --type <filetype> Filter by type: file (f), directory (d/dir), symlink (l),
executable (x), empty (e), socket (s), pipe (p), char-device
(c), block-device (b)
-e, --extension <ext> Filter by file extension
-S, --size <size> Limit results based on the size of files
--changed-within <date|dur> Filter by file modification time (newer than)
--changed-before <date|dur> Filter by file modification time (older than)
-o, --owner <user:group> Filter by owning user and/or group
--format <fmt> Print results according to template
-x, --exec <cmd>... Execute a command for each search result
-X, --exec-batch <cmd>... Execute a command with all search results at once
-c, --color <when> When to use colors [default: auto] [possible values: auto,
always, never]
-h, --help Print help (see more with '--help')
-V, --version Print version
基准测试
让我们搜索我的家目录中所有以[0-9].jpg
结尾的文件。它包含约750,000个子目录和约4000万个文件。为了平均和统计分析,我使用了hyperfine。以下基准测试是在“预热”/预先填充的磁盘缓存下进行的(对于“冷”磁盘缓存的测试结果显示出相同趋势)。
让我们从find
开始
Benchmark 1: find ~ -iregex '.*[0-9]\.jpg$'
Time (mean ± σ): 19.922 s ± 0.109 s
Range (min … max): 19.765 s … 20.065 s
find
在不需要执行正则表达式搜索时速度要快得多
Benchmark 2: find ~ -iname '*[0-9].jpg'
Time (mean ± σ): 11.226 s ± 0.104 s
Range (min … max): 11.119 s … 11.466 s
现在让我们尝试相同的fd
。请注意,fd
默认执行正则表达式搜索。这里需要-u/--unrestricted
选项进行公平的比较。否则,fd
不需要遍历隐藏文件夹和忽略路径(见下文)
Benchmark 3: fd -u '[0-9]\.jpg$' ~
Time (mean ± σ): 854.8 ms ± 10.0 ms
Range (min … max): 839.2 ms … 868.9 ms
对于这个特定的例子,fd
大约比 find -iregex
快 23 倍,比 find -iname
快约 13 倍。顺便说一句,这两个工具都找到了完全相同的 546 个文件 😄。
注意:这是在 一台特定 机器上进行的 一个特定 性能基准测试。虽然我们已经进行了许多不同的测试(并找到了一致的结果),但结果可能因人而异!我们鼓励每个人都亲自尝试。查看 这个存储库 获取所有必要的脚本。
关于 fd 的速度,很多功劳要归功于那些在 ripgrep(去看看!)中也被使用的 regex
和 ignore
仓库。
故障排除
fd
找不到我的文件!
请记住,fd
默认会忽略隐藏目录和文件。它也会忽略 .gitignore
文件中的模式。如果你想要确保找到所有可能的文件,请始终使用 -u
/--unrestricted
选项(或使用 -HI
来启用隐藏和忽略的文件)
> fd -u …
彩色输出
fd
可以根据扩展名着色文件,就像 ls
。为了让这起作用,必须设置环境变量 LS_COLORS
。通常,这个变量的值由 dircolors
命令设置,该命令提供了一种方便的配置格式来为不同的文件格式定义颜色。在大多数发行版中,LS_COLORS
已经设置好了。如果你使用的是 Windows 或者如果你正在寻找更完整(或更丰富多彩)的替代方案,请查看 这里,这里 或 这里。
fd
也尊重 NO_COLOR
环境变量。
fd
似乎没有正确解释我的正则表达式模式
许多特殊的正则表达式字符(如 []
,^
,$
等)在您的 shell 中也是特殊字符。如果有疑问,请始终确保将单引号放在正则表达式模式周围
> fd '^[A-Z][0-9]+$'
如果你的模式以连字符开头,你必须添加 --
来表示命令行选项的结束。否则,模式将被解释为一个命令行选项。或者,使用包含单个连字符字符类的字符
> fd -- '-pattern'
> fd '[-]pattern'
alias
或 shell 函数的 "命令未找到" 错误
Shell 的别名(alias)和函数不能用于通过 fd -x
或 fd -X
执行命令。在 zsh
中,你可以通过 alias -g myalias="…"
命令将别名设置为全局。在 bash
中,你可以使用 export -f my_function
将其用于子进程。你仍然需要调用 fd -x bash -c 'my_function "$1"' bash
。对于其他用例或shell,请使用(临时)shell脚本。
与其他程序集成
使用 fd 与 fzf
你可以使用 fd 为命令行模糊搜索器 fzf 生成输入。
export FZF_DEFAULT_COMMAND='fd --type file'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
然后,你可以在终端中键入 vim <Ctrl-T>
以打开 fzf 并搜索 fd 的结果。
或者,你可能更喜欢跟随符号链接并包含隐藏文件(但排除 .git
文件夹)
export FZF_DEFAULT_COMMAND='fd --type file --follow --hidden --exclude .git'
你甚至可以在 fzf 中使用 fd 的彩色输出,通过设置
export FZF_DEFAULT_COMMAND="fd --type file --color=always"
export FZF_DEFAULT_OPTS="--ansi"
有关更多详细信息,请参阅 fzf README 中的 技巧部分。
使用 fd 与 rofi
rofi 是一个图形化启动菜单应用程序,能够通过读取 stdin 来创建菜单。将 fd
的输出通过管道传输到 rofi
的 -dmenu
模式,可以创建模糊搜索的文件和目录列表。
示例
创建一个不区分大小写的多选列表,列出位于你的 $HOME
目录下的 PDF 文件,并使用你配置的 PDF 查看器打开选择。要列出所有文件类型,请省略 -e pdf
参数。
fd --type f -e pdf . $HOME | rofi -keep-right -dmenu -i -p FILES -multi-select | xargs -I {} xdg-open {}
要修改 rofi 显示的列表,请向 fd
命令添加参数。要修改 rofi 的搜索行为,请向 rofi
命令添加参数。
使用 fd 与 emacs
emacs 包 find-file-in-project 可以使用 fd 来查找文件。
安装 find-file-in-project
后,将行 (setq ffip-use-rust-fd t)
添加到你的 ~/.emacs
或 ~/.emacs.d/init.el
文件。
在 emacs 中,运行 M-x find-file-in-project-by-selected
以查找匹配的文件。或者,运行 M-x find-file-in-project
以列出项目中的所有可用文件。
以树状结构打印输出
要将 fd
的输出格式化为文件树,可以使用带有 --fromfile
的 tree
命令。
❯ fd | tree --fromfile
这比单独运行 tree
更有用,因为默认情况下 tree
会忽略任何文件,并且它支持比 fd
更丰富的选项集来控制要打印的内容。
❯ fd --extension rs | tree --fromfile
.
├── build.rs
└── src
├── app.rs
└── error.rs
在 bash 和类似系统中,你可以简单地创建一个别名
❯ alias as-tree='tree --fromfile'
使用 fd 与 xargs
或 parallel
结合使用
请注意,fd
有内置的 命令执行 功能,可以通过其 -x
/--exec
和 -
/--exec-batch
选项来执行。如果您愿意,仍然可以与 xargs
结合使用。
> fd -0 -e rs | xargs -0 wc -l
在这里,-0
选项告诉 fd 按照空字符(而不是换行符)来分隔搜索结果。同样,xargs
的 -0
选项告诉它以这种方式读取输入。
安装
在 Ubuntu 上
... 以及其他基于 Debian 的 Linux 发行版。
如果您运行的是 Ubuntu 19.04(Disco Dingo)或更高版本,您可以安装 官方维护的软件包
apt install fd-find
请注意,二进制文件名为 fdfind
,因为 fd
已经被另一个软件包使用。建议安装后,通过执行命令 ln -s $(which fdfind) ~/.local/bin/fd
为 fd
添加一个链接,以便像本文档中一样使用 fd
。确保 $HOME/.local/bin
在您的 $PATH
中。
如果您使用的是较旧的 Ubuntu 版本,您可以从 发布页面 下载最新的 .deb
软件包,并通过以下方式安装:
dpkg -i fd_9.0.0_amd64.deb # adapt version number and architecture
在 Debian 上
如果您运行的是 Debian Buster 或更高版本,您可以安装 官方维护的 Debian 软件包
apt-get install fd-find
请注意,二进制文件名为 fdfind
,因为 fd
已经被另一个软件包使用。建议安装后,通过执行命令 ln -s $(which fdfind) ~/.local/bin/fd
为 fd
添加一个链接,以便像本文档中一样使用 fd
。确保 $HOME/.local/bin
在您的 $PATH
中。
在 Fedora 上
从 Fedora 28 开始,您可以从官方软件包源安装 fd
dnf install fd-find
在 Alpine Linux 上
如果您已启用适当的存储库,您可以从官方源安装 fd 软件包
apk add fd
在 Arch Linux 上
您可以从官方仓库安装 fd 软件包
pacman -S fd
在 Gentoo Linux 上
您可以使用官方仓库中的 fd ebuild
emerge -av fd
在 openSUSE Linux 上
您可以从官方仓库安装 fd 软件包
zypper in fd
在 Void Linux 上
您可以通过 xbps-install 安装 fd
xbps-install -S fd
在 ALT Linux 上
您可以从官方仓库安装 fd 软件包
apt-get install fd
在 Solus 上
您可以从官方仓库安装 fd 软件包
eopkg install fd
在 RedHat Enterprise Linux 8/9 (RHEL8/9)、Almalinux 8/9、EuroLinux 8/9 或 Rocky Linux 8/9 上
您可以从 Fedora Copr 安装 fd 包。
dnf copr enable tkbcopr/fd
dnf install fd
还有使用 较慢的 malloc(而不是 jemalloc)的不同版本的 fd-find
包,该版本可以从 EPEL8/9 仓库获取。
在 macOS 上
您可以使用 Homebrew 安装 fd
。
brew install fd
… 或者使用 MacPorts
port install fd
在 Windows 上
您可以从 发布页面 下载预编译的二进制文件。
或者,您可以通过 Scoop 安装 fd
。
scoop install fd
或者通过 Chocolatey。
choco install fd
或者通过 Winget。
winget install sharkdp.fd
在 GuixOS 上
您可以从官方仓库安装 fd 包。
guix install fd
在 NixOS / 通过 Nix
您可以使用 Nix 包管理器 安装 fd
。
nix-env -i fd
在 FreeBSD 上
您可以从官方仓库安装 fd-find 包。
pkg install fd-find
从 npm
在 Linux 和 macOS 上,您可以安装 fd-find 包。
npm install -g fd-find
从源码
使用 Rust 的包管理器 cargo,您可以通过以下方式安装 fd:
cargo install fd-find
请注意,需要 rust 版本 1.77.2 或更高版本。
构建还需要 make
。
从二进制文件
发布页面包括 Linux、macOS 和 Windows 的预编译二进制文件。静态链接的二进制文件也是可用的:文件名中包含 musl
的存档文件。
开发
git clone https://github.com/sharkdp/fd
# Build
cd fd
cargo build
# Run unit tests and integration tests
cargo test
# Install
cargo install --path .
维护者
许可
fd
在 MIT 许可证和 Apache License 2.0 的条款下分发。
有关许可详情,请参阅 LICENSE-APACHE 和 LICENSE-MIT 文件。
依赖项
~11–23MB
~334K SLoC