March 15, 2018

Bash Shell Tweaks & Tips

UPDATED JUNE 2023

Bash is the most common Unix shell. Bash is ubiquitous due to it being the default user shell for various flavours of Unix including: Linux, macOS (prior to Catalina) and the Windows Subsystem for Linux (WSL).

Due to this ubiquity, and the need to maintain backward compatibility, it is rare that newer features of Bash are enabled by default. Some mistake this lack of default change for stagnation and simply move across to a different shell such as Zsh or Fish for their productivity enhancements.

This post will document a number of simple tweaks and tips, gleamed from the interwebs, that will improve user productivity when using Bash. A special note should be given to the Sensible Bash project for providing a couple noteworthy tips.

Many tweaks n’ tips noted in this post are baked into my bashrc and inputrc files.

macOS, upgrade to Bash 5.x

macOS by default ships with a very old version of Bash, version 3.2, due to licensing reasons. That version is well over a decade old with many missing features.

Please upgrade to version 5.x of Bash. That is most easily accomplished by using the Homebrew package manager.

Install Homebrew followed by:

brew install bash
sudo sh -c 'echo /usr/local/bin/bash >> /etc/shells'
chsh -s /usr/local/bin/bash

Launch a new shell and enter echo $SHELL, it should list /usr/local/bin/bash.

I also recommend reading this post followed by installation of the GNU command line utilities for macOS.

bash-completion

Out of the box Bash only provides rudimentary filesystem based completions unlike the Zsh and Fish shells which offer command-aware completions. For example, shopt cd<TAB> should command-aware complete with the options of cdable_vars or cdspell as compared to completing with filenames or directories starting with cd (which is what standard Bash will do).

The bash-completion packages extends the Bash shell with intelligent completions for many common commands.

Most Linux distributions install and enable bash-completion these days.

Homebrew based Bash on macOS on the other hand will require bash-completion installation and invocation.

First install bash-completion version 2:

brew install bash-completion@2

Then source bash-completion in your ~/.bashrc file:

[[ -r "$HOMEBREW_PREFIX/etc/profile.d/bash_completion.sh" ]] && . "$HOMEBREW_PREFIX/etc/profile.d/bash_completion.sh"

Confirm that bash-completion is enabled by trying the shopt cd<TAB> example noted above, the aim is to have the cdable_vars and cdspell options displayed.

If you have never used command-aware completion before it will be a revelation how useful this capability is especially for commands such as git and ssh. Basically you want to hit the TAB key early and often.

Readline Configuration

The GNU Readline library is used by Bash, and certain other utilities, for line-editing and history management.

This library is configured by an .inputrc file in a user’s home directory. A list of recommended ~/.inputrc settings follows.

Readline Shortcuts

The Readline library also provides a number of useful default shortcuts.

Bash Settings

A more productive Bash experience is achieved by enabling and using the newer features the shell has made available.

The Bash shell is configured through a .bashrc file in a user’s home directory. A list of recommended ~/.bashrc tweaks follows.

Useful Bash Aliases

A Bash alias is a user defined shortcut. Aliases save keystrokes. Do not be afraid to alias long commands with shorter aliases, they will save you time.

As a starting point, here are some of the aliases from my ~/.bashrc file.

The z Directory Navigation Utility

There are a number of ways to navigate a file system: plain cd, pushd/popd, or defining a CDPATH environment variable as a short-circuit base directory.

The z utility provides a quicker way to change to an already visited directory. The z utility, which works in both Bash and Zsh, tracks the directories you visit with the cd command. Once trained, you can just use the z command with a portion of a path to jump to a visited directory.

UPDATE (JUN 2023): I now use zoxide instead of z. In practice they operate nearly the same.

The z utility is most easily installed with Homebrew:

brew install z

Install the old-fashioned way if you are not a Brew user.

Then source the z.sh file in your ~/.bashrc file:

. $(brew --prefix)/etc/profile.d/z.sh

Usage

First you need to train z:

cd ~/dotfiles
cd ~/projects/tickets_app
cd ~/projects/tickets_app/src
cd ~/projects/tickets
cd ~/projects/tickets/src

Now you can jump using the z command with the desired path hints:

z dot         # will jump to ~/dotfiles
z tic         # will jump to ~/projects/tickets
z tic app     # will jump to ~/projects/tickets_app
z tic app src # will jump to ~/projects/tickets_app/src

Though not Bash specific, the z utility is a fantastic tool that all Bash users will find useful.

:bomb: z by default will hook into the PROMPT_COMMAND environment variable to record cd events (the training phase). This connection may not exist when using a custom prompt script such as seafly. In that case I recommend the following settings:

_Z_NO_PROMPT_COMMAND=1
. $(brew --prefix)/etc/profile.d/z.sh
alias c='_f(){ cd "$@" && _z --add "$(pwd)"; }; _f'

Use the c command to record directory changes in the z database (aka training).

The fzf Utility

The fzf utility is a general-purpose line-oriented fuzzy finding command line tool.

The following posts detail some of the capabilities of fzf:

With respect to Bash and fzf, I do recommend sourcing the fzf Bash keybindings in ~/.bashrc. For example, with a Homebrew installation of fzf that would be:

. $(brew --prefix)/opt/fzf/shell/key-binding.bash

Once sourced the following handy fzf key-bindings are available in the Bash command line:

The qmv Rename Utility

The qmv utility is used to rename files by way of an auto-generated document of filenames that will be opened in your preferred editor; the renames will be applied after the editor has exited. This utility is especially useful for bulk renames where the power of editor substitution can be used to quickly specify the desired renames.

qmv installation for macOS via Homebrew:

brew install renameutils

Linux (Debian flavoured) installation:

sudo apt install renameutils

By default, qmv will use two editor columns, in my experience this consumes too much valuable real-estate for little benefit, hence, I recommend the following Bash alias (force destination-only):

alias qmv='qmv -d -f do'

Usage

qmv **/*.JPG # rename to lowercase '.jpg' extension via substitution
qmv *.old    # rename to '.BAK' extension also via substitution

Like the z utility noted above, this qmv utility is not Bash specific, but it will also prove very useful to all Bash users.

Style

If you spend a lot of time in the command line, then I recommend styling the terminal to suit your needs.

Some suggestions:

Conclusion

With just a little effort the Bash shell will become a more enjoyable and productive environment.