Modern command line tools

In this session we’ll treat the fish shell, and the command line utilities ripgrep, and fzf. All are installed on Kapteyn machines by default.

SSH config

The computer group has a great ssh how-to for setting up your ssh config file.

fish shell

fish is “a command line shell for the 90s”. Why would you want to use fish? Well, in their own words:

fish is a fully-equipped command line shell (like bash or zsh) that is smart and user-friendly. fish supports powerful features like syntax highlighting, autosuggestions, and tab completions that just work, with nothing to learn or configure.

If you want to make your command line more productive, more useful, and more fun, without learning a bunch of arcane syntax and configuration options, then fish might be just what you’re looking for!

Screencast

Hands-on

We’ll follow the fish tutorial closely. The things we’ll treat are:

  • Syntax highlighting: invalid commands are colored red, valid paths are underlined.

  • Autosuggestions: suggestions are shown in gray. It knows about commands, paths, options, and history! They can be accepted with -> or Alt + -> (first word).

  • Tab completions: press Tab and fish will attempt to complete the command, argument, or path.

  • cdh to switch recent directories.

It’s a bit different from most other shells though. For example:

  • Variables are set with set. Type man set or help set.

  • Exit status is stored in $status instead of $?

  • Command substitution is done with parentheses, not braces.

oh-my-fish

To get the most out of fish, I would recommend installing a fish package manager. The one I use is oh-my-fish.

Amongst other, this allows you to easily switch themes:

$ omf theme [<theme>]

or install additional plugins:

$ omf install [<name>|<url>]

I use the z extension ($ omf install z).

Default shell

Visit https://ipaserver.intra.astro.rug.nl to make fish your default shell for Kapteyn machines.

ripgrep

ripgrep recursively searches directories for a regex pattern.

From the documentation:

ripgrep is a command line tool that searches your files for patterns that you give it. ripgrep behaves as if reading each file line by line. If a line matches the pattern provided to ripgrep, then that line will be printed. If a line does not match the pattern, then the line is not printed.

Basically, it’s a super-fast grep replacement that filters git ignore files by default.

Screencast

Hands-on

Try to find all Python import statements:

# First switch to the directory containing code.
$ z euclid/euclid
$ rg import

Note that by default it does a recursive search. The result is a bit too broad, as there are also Typescript hits:

$ rg -l import

So let’s only do Python files:

$ rg --type py import

There are still some unwanted hits, from non-import statements. The ripgrep search pattern is interpreted as a regex, so let’s write a more restrictive pattern:

$ rg --type py '(^import)|(^from .* import)'

ripgrep can do replacement capturing groups. So if we want to list all imported packages, we could do:

$ rg --type py -o '(?:^import (.*))|(?:^from (.*) import)' -r '$1$2'

And to clean it up further:

$ rg --type py -o --no-filename '(?:^import (.*))|(?:^from (.*) import)' -r '$1$2' \
  | tr ',' '\n' | awk '{$1=$1};1' | sort | uniq | rg '\.|\sas\s' --invert-match

Lastly, ripgrep also takes input from stdin:

$ ls -l | rg serv

But for that you might also want to consider tools like fzf.

fzf

fzf is a command-line fuzzy finder. It’s an interactive Unix filter for command-line that can be used with any list; files, command history, processes, hostnames, bookmarks, git commits, etc.

Screencast

Hands-on

Let’s filter something:

$ ls -l | fzf serv

or

$ yes | head -10 | awk '{ print NR, NR % 2 ? "even" : "odd" }' | fzf

Or you can use it to search in all the running processes:

$ ps -ef | fzf

Of course printing out the full ps output is not very convenient, so we can awk to only print the process ID and then kill it:

$ ps -ef | sed 1d | fzf | awk '{print $2}' | xargs kill -9

A common use case is browsing files with it. In fact, it will search all files in the current directory if you open it without arguments:

$ fzf

It will print out the selected option when hitting enter. You can also select multiple items with Tab if you specify the multi option.

$ fzf --multi

You can e.g. open a files via command substitution:

$ vim (fzf)

This is so common there’s a handy shortcut for it, ctrl-t:

$ vim @{key CTRL-T}

You can also fuzzy-search your command history with ctrl-r:

$ @{key CTRL-P}

although this doesn’t add much to the default fish behaviour. Lastly, you can easily jump directory with alt-c:

$ @{key ALT-C}

although I tend to use z for this purpose.