Enhancing commands with FZF

I spent a lot of time on optimizing the commands that I use on a daily basis. I keep all of these in a dotfiles repository.

There is one tool that I’ve been incorporating little by little into my daily flow, which is called FZF. FZF is a command-line fuzzy finder. In itself that might not be too useful, but combined with other commands is where it truly shines. The repository itself has a lot of examples on how to achieve various things with it.

One common pattern I’ve seen in using FZF to enhance commands is, that there are a lot of commands which normally accept one or more argument in terms of a filename. Think of rm for example. This command does nothing but print the manual if you execute it without any commands.

Given that, we can create a simple function which will execute FZF to find the file that you want to delete whenever we execute rm without any arguments. Executing rm with any arguments will still function the same.

Lets dive into the code for this.

function rm {
  if [[ "$#" -eq 0 ]]; then
    local files
    files=$(ls | fzf --multi)
    echo $files | xargs rm
  else
    command rm "$@"
  fi
}

This command checks the amount of arguments to see if they are equal to zero. If they are not, we issue the normal command, we use command rm "$@" here otherwise it would recursively call this function.

If there are zero arguments however we do a few things:

  1. Create a variable which gets the list of files that we select with FZF.
  2. We pass the —multi option to FZF so that we can select multiple options. Selecting/deselecting is done by pressing Tab and moving around the list of items is done by using the arrow keys. Enter will save the selection and exit FZF.
  3. These selected files will be passed to the rm command.

Currently it would only look for the files which are one layer deep, since I’ve used ls | fzf --multi here. I’m just piping the output of ls into FZF to do a fuzzy search on.

If you want to search for all files recursively, fzf --multi without ls will do exactly that.

This pattern can be applied to any command that does nothing when used without any arguments, but will execute the command when passed in some arguments. The benefit here is that you won’t have to learn any new commands since it’ll just use the same name as the command you are already using.

Published 4 May 2020

I blog about Android.
Joey Kaan on Twitter