Using fzf to quick access my notes from the cli

I wanted to create a simple script to quickly access my notes from the command line. fzf is a great and flexible tool which can be used to fuzzy search in the given input, like the file names in my notes directory. I already use it to search in the command line history and in vim to open files with fzf.vim. In this post I will walk you through how I built my note script using fzf.

Building the script

Executing the command fzf in the cli without any options will list all the files for the current and every sub directory. The first thing I do in the script is to change the directory where I store my notes and execute fzf.

#!/bin/bash

notes_dir="$HOME/notes"
cd $notes_dir

I will need the output of fzf and the exit code later so I save them too.

fzf_output=$(fzf)
exit_code=$?

fzf options

fzf has many customization options how to show the results. One of the most important one for this script is the --print-query option which prints the query what we typed in so it can be used to create a new file if there is no match. The value of the query is printed before the match in a new line in the fzf output.

Additionally to the --print-query option I use some styling options like: --border and the --preview to show the first 20 lines from a note. My final version with all the parameters of the executed fzf command looks like this:

fzf_output=$(fzf --reverse --prompt=$notes_dir/ --border --print-query --preview="head -n 20 {+}" --preview-window=down:50% --inline-info)

The full list of options can be listed with the fzf --help command and by viewing the man page for fzf (man fzf).

Process the output from fzf

To work with output of the fzf command I will split the output into an array in the bash script, where the query we typed in will be the first line and if there is a match it will be printed in the second line.

# split the output into an array
readarray -t y <<<"$fzf_output"

query=${y[0]} # query is the firts line
match=${y[1]} # match is the second line if there is any

Open or create a note

fzf has multiple exit codes which is very great if we want to build additional tooling around it.

0      Normal exit
1      No match
2      Error
130    Interrupted with CTRL-C or ESC

Based on the exit code the script will decide what to do. Open an existing note or to create a new. Using the $EDITOR environment variable will make it more flexible. No change is needed if some other editor is set in the environment.

if [[ 0 -eq $exit_code ]]; then
  # open the matched file with an editor
  $EDITOR $notes_dir/$match
elif [[ 1 -eq $exit_code ]]; then
  # create a new md file where the file name will be the query
  $EDITOR $notes_dir/$query.md
fi

The whole script

After going through on each part this is the whole script.

#!/bin/bash

notes_dir="$HOME/notes"
cd $notes_dir

fzf_output=$(fzf --reverse --prompt=$notes_dir/ --border --print-query --preview="head -n 20 {+}" --preview-window=down:50% --inline-info)
exitcode=$?

# --print-query prints the query which can be used
# to create a new file if there is no match
# in this case the query is printed before a match in a new line

# split the output into an array
readarray -t y <<<"$fzf_output"

query=${y[0]} # query is the firts line
match=${y[1]} # match is the second line if there is any

# Exit codes
#0      Normal exit
#1      No match
#2      Error
#130    Interrupted with CTRL-C or ESC
if [[ 0 -eq $exitcode ]]; then
  # open the matched file with an editor
  $EDITOR $notes_dir/$match
elif [[ 1 -eq $exitcode ]]; then
  # create a new md file where the file name will be the query
  $EDITOR $notes_dir/$query.md
fi

Conclusion

As you can see it is very easy to create additional scripts around fzf to improve your cli environment. There are many great fzf examples worth checking out (docker, git …) if you want to improve your cli tools.