如何从当前工作目录的另一个目录启动 fzf?

How to start fzf from another directory the the current working directory?

我经常使用 fzf 来浏览文件系统,尤其是 Alt-c 键绑定。

调用时,fzf 从当前工作目录生成一个列表。

是否可以fzf从指定目录生成列表?

我已尝试 fzf <dir>,但它会导致错误(未知选项)。此外,我找不到用于指定起始目录的任何选项,例如 -C <dir>

我遇到了一个更普遍的问题,可能对您有用。以下是我写的一篇blog post

配置 FZF 以搜索工作目录以外的有用目录

我将 fzf 用作命令行工具,并在 Vim 中使用 fzf.vim 插件。它使查找(和打开)文件变得直观、快速,并且使您无需记住它们的位置或确切名称。默认情况下,fzf 在当前目录中递归搜索,这通常正是您想要的。如果您需要在当前工作目录之外的某个目录中搜索文件,您需要将该路径指定为 fzf 的参数,之后一切照常(fzf 将递归搜索指定目录)。

问题

偶尔必须精确指定路径才能进行模糊搜索,这总是让人感到羞耻...精确指定路径正是 fzf 应该为您减轻负担的东西!我最初的方法是提供主目录路径并让 fzf 搜索所有内容,主目录路径可以仅用几个字符指定,因此在这种情况下没有真正的负担。

这样做的问题是您最终搜索了很多您知道没有您想要的文件的目录。主要罪魁祸首是安装 anaconda3 时最终得到的目录。结果将被数千个内部文件淹没,路径很长。长路径倾向于 'soak up' 我在搜索中输入的任何字母,因此 fzf 很难过滤掉它们。

解决方案

您可以选择 fzf 在后台使用的搜索工具。默认是标准的 linux find 命令,但您也可以使用 fd、ripgrep 或 silver searcher。除了比默认查找快得多之外,后面这些工具还尊重 .gitignore 文件。这意味着 fzf 将跳过 .gitignore 文件中列出的任何文件或目录。我们可以将此功能转化为我们的优势。

首先,我们安装fd。如果你 运行 Ubuntu 19.04 (Disco Dingo) 或更新版本,你可以安装官方维护的包:

sudo apt install fd-find

如果您使用旧版本的 Ubuntu,您可以从发布页面下载最新的 .deb 包并通过以下方式安装:

# adapt version number and architecture
sudo dpkg -i fd_8.2.1_amd64.deb

现在我们通过在 .bashrc 中添加以下行来配置 fzf 以使用 fd:

export FZF_DEFAULT_COMMAND="fdfind . $HOME"

如果您使用的版本比 Ubuntu 19.10 旧,则需要像这样修改上面的行:

export FZF_DEFAULT_COMMAND="fd . $HOME"

现在 fzf 将始终从主目录递归搜索,并尊重任何 git 忽略任何 git 存储库中的文件。 fzf 通过查找 .git 目录来检测 git 存储库。我们可以通过创建 .git 目录在我们的主目录中触发此行为。为此,您的主目录不能已经是 git 存储库,但我认为没有人这样做...然后我们可以创建一个 .gitignore 文件来忽略我们认为的任何目录想要 - 即淹没我们搜索的那些:

cd ~/
mkdir .git
touch .gitignore

我发现我可能(~15)想用 fzf 递归搜索的目录列表比我永远不想搜索的目录列表短。我要搜索的目录中的文件总数大约是 5000 个左右 - fd 轻松处理。

在 .gitignore 文件中,我首先列出了我所有的主目录,每个主目录后跟一个“/”:

# start by igoring every home directory
anaconda3/
arch/
cache/
code/
Desktop/
  .
  .
  .

然后在这些目录下面,放上你要搜索的目录,每个目录前面都有一个'!'然后是 '/':

# now un-ignore the ones I care about
!code/
!Desktop/
!documents/
!downloads/
  .
  .
  .

'!'将 'cancel out' 忽略之前的命令。

我们已经有了。我们可以在文件系统中的任何位置调用 fzf 并开始输入关于我们想到的文件的模糊内容,fzf 将在一组预定义的目录中搜索并轻松找到它。这完全消除了思考文件可能在哪里以及它的命名方式的障碍。

N.B。我注意到,出于某种原因,有几个子目录没有出现在 fzf 搜索中,因此我在本节中明确创建了一些 '!path/to/missed/directory/' 行...

N.B。您可能想知道“如果我发现自己在一个不在列表中的常用目录中,并且想使用 fzf 怎么办?”。我也有同样的担忧,所以我在我的 .bashrc 中放置了几个别名,可以随意打开和关闭上述配置(请务必对 Ubuntu 19.10+ 使用 'fdfind',如上所示) :

# restore fzf default options ('fzf clear')
alias fzfcl="export FZF_DEFAULT_COMMAND='fd .'"

# reinstate fzf custom options ('fzf-' as in 'cd -' as in 'back to where I was')
alias fzf-="export FZF_DEFAULT_COMMAND='fd . $HOME'"

如果您使用 Vim 创建 .gitignore 文件,获取主目录中所有目录列表的简单方法是以下命令:

:.!ls ~/

通过将光标放在列表中的第一个目录并输入以下命令,将“/”附加到所有行:

:.,$ norm A/

与上面类似,插入 '!'通过将光标放在列表中的第一个目录并输入以下命令,在每个目录之前:

:.,$ norm I!

假设您使用的是 bash 或类似的,这是内置于随 fzf 安装的默认完成选项中的:https://github.com/junegunn/fzf#fuzzy-completion-for-bash-and-zsh

tldr;输入起始文件或目录,附加 ** 并点击 Tab。因此,如果您输入 cd /foo/**,则选项卡将以 /foo 作为起始目录打开 fzf。

编辑 在编写命令时将其硬编码在 fzf's bash helpers 中,这就是为什么它适用于 catcd 但不适用于 tacnano。这是完整列表:

awk cat diff diff3
emacs emacsclient ex file ftp g++ gcc gvim head hg java
javac ld less more mvim nvim patch perl python ruby
sed sftp sort source tail tee uniq vi view vim wc xdg-open
basename bunzip2 bzip2 chmod chown curl cp dirname du
find git grep gunzip gzip hg jar
ln ls mv open rm rsync scp
svn tar unzip zip

要添加其他命令,请在例如你的 .bashrc,在 fzf 获取来源的地方之后(类似于 [ -f ~/.fzf.bash ] && source ~/.fzf.bash):

__fzf_defc "tac" _fzf_path_completion "-o default -o bashdefault"

或者:打开一个问题来询问你想要默认添加到 fzf 的命令,反正 tac 和 nano 之类的东西非常常见。