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

问题描述

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

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

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

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

解决方法

我有一个更一般的问题,可能对您有用。以下是我写的关于它的blog post

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

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

问题

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

这样做的问题是你最终会搜索很多你知道没有你想要的文件的目录。如果您安装 anaconda3,主要的违规者是您最终得到的目录。结果将被数千个内部文件淹没,路径很长。长路径倾向于“吸收”我在搜索中输入的任何字母,因此 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 存储库中的任何 .gitignore 文件。 fzf 通过查找 .git 目录来检测 git 存储库。我们可以通过创建一个 .git 目录在我们的主目录中触发这种行为。为了实现这一点,你的主目录不能已经是一个 git 存储库,但我认为没有人这样做......然后我们可以创建一个 .gitignore 文件来忽略我们想要的任何目录 - 即那些淹没我们搜索的目录:

cd ~/
mkdir .git
touch .gitignore

我发现我可能想用 fzf 递归搜索的目录列表 (~15) 比我不想搜索的目录列表短。我要搜索的目录中的文件总数约为 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/
  .
  .
  .

'!'将“取消”之前的忽略命令。

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

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

注意您可能想知道“如果我发现自己位于不在列表中的常用目录中,并且想要使用 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/**,则选项卡将打开 fzf,并将 /foo 作为起始目录。

edit 在编写此工作的命令时在 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 之类的东西无论如何都非常常见。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...