Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Customise Bash: .bashrc, prompt, bash-it and fzf

By updated

Improve this page

bash logo

Customising Bash fits in one file: ~/.bashrc. That is where you put your aliases, your PS1 prompt, your functions and your environment variables, read again by every terminal. Bash is the default shell of Debian, Ubuntu and RHEL; macOS, for its part, switched to Zsh in 2019. This page shows the useful settings by hand, then two tools that go further: bash-it for themes and plugins, fzf to search the history. The behaviours described were checked on Debian 13, Ubuntu 24.04 and AlmaLinux 10.

What you will learn

  • Configure .bashrc to customise the prompt, aliases and functions
  • Customise the PS1 prompt to show useful information
  • Install and use bash-it to manage themes and plugins
  • Integrate fzf for ultra-fast fuzzy search in the history and in files

History of Bash

Bash, short for "Bourne Again Shell", was released in 1989 by Brian Fox for the GNU project. It succeeds Stephen Bourne's sh, whose syntax it keeps to stay compatible with existing scripts, adding history, completion and many extensions.

Its inclusion in the GNU project made it the natural shell of Linux distributions, and it was long the shell of macOS, until Apple replaced it with Zsh in 2019. Compared with Zsh, Ksh or Tcsh, Bash stands out for its balance between simplicity and features, and above all for its guaranteed presence on servers: it is the shell your administration scripts can assume is available.

Install Bash and configure the shell on Linux

Bash is preinstalled on the three reference distributions: there is nothing to install. Its version shows with bash --version, useful to know whether a recent feature is available. Measured: 5.2.37 on Debian 13, 5.2.21 on Ubuntu 24.04, 5.2.26 on AlmaLinux 10.

Terminal window
bash --version

How to set Bash as the default shell on Linux

Your login shell is recorded in /etc/passwd, and chsh -s changes it for your account. The command asks for your password, and for an ordinary user only accepts the shells listed in /etc/shells.

Terminal window
chsh -s "$(command -v bash)"

chsh is provided by the passwd package on Debian and Ubuntu, by util-linux on AlmaLinux 10. The change applies to the next logins: check it with getent passwd "$USER", whose line must end with the path of Bash.

Customise Bash: tips for the .bashrc file

The ~/.bashrc file is read by every interactive shell that is not a login shell, that is by every terminal you open in a graphical session. Login shells (SSH, console) first read another file, but distributions make them load .bashrc in turn: ~/.profile does so on Debian and Ubuntu, ~/.bash_profile on RHEL and its derivatives (checked in /etc/skel).

Located in your home directory, .bashrc only concerns your account. You define environment variables, aliases, functions and the prompt there; each one has a section below.

Add aliases to simplify commands

Aliases are shortcuts for the commands you type often. They are declared in .bashrc, one per line, with single quotes around the command:

Terminal window
# Alias to show hidden files in long format
alias ll='ls -la'
# Aliases to navigate quickly
alias ..='cd ..'
alias ...='cd ../..'
# Alias for complex commands (Debian and Ubuntu)
alias update='sudo apt update && sudo apt upgrade -y'

An alias added to the file does not exist yet in the open terminal: reload .bashrc to apply it, or open a new terminal. The workings of apt used here are detailed in the apt guide.

Terminal window
source ~/.bashrc

Customise the Bash prompt

The prompt is the line shown before each command. It is set with the PS1 variable, whose backslash sequences are replaced when it is displayed:

Terminal window
# Prompt showing the user, the host and the current directory
export PS1='\u@\h:\w\$ '

In this example, three sequences are enough to locate the session:

  • \u stands for the user name.
  • \h stands for the host name.
  • \w stands for the current working directory.

To add colours, you insert ANSI codes, surrounded by \[ and \]: these markers tell Bash that the characters take no room on screen, otherwise long commands wrap badly.

Terminal window
export PS1='\[\e[32m\]\u@\h:\[\e[34m\]\w\[\e[0m\]\$ '

This prompt colours the user and the host in green (32), the directory in blue (34), then returns to the default colour with \e[0m.

Add custom functions

Functions group several commands under a name, and accept arguments where an alias cannot. For example, a function that empties a temporary directory:

Terminal window
clean_temp() {
rm -rf ~/temp/*
echo "Temporary folder cleaned."
}

Add it to your .bashrc, then reload it with source ~/.bashrc to use it. Functions are detailed in Bash functions, with their scope traps.

Change environment variables

.bashrc is also used to define environment variables, passed on to the programs you start. The most common case is adding a directory to the PATH:

Terminal window
# Add directories to the PATH
export PATH=$PATH:/usr/local/bin:/opt/scripts

Watch out for a side effect: each source ~/.bashrc adds these directories to the PATH again, which grows with duplicates as you reload. It does no serious harm, but opening a new terminal starts again from a clean PATH.

bash-it: a framework to customise Bash easily

Overview

bash-it is an open source framework that brings together, for Bash, ready-to-use aliases, plugins, prompt themes and completions. It saves you configuring everything by hand, at the cost of a GitHub repository cloned in your home directory.

It is made of four families of modules, which can be turned on one by one with bash-it enable:

  • Aliases: predefined shortcuts to simplify common commands.
  • Plugins: modules that add specific features (e.g. Git, Docker support).
  • Themes: customisation of the prompt to make the terminal more informative and good-looking.
  • Completions: improvements of autocompletion for complex commands.

Install and configure bash-it

The installation takes four steps, without root rights: clone the repository, run its installation script, turn it on in .bashrc, then reload.

  1. Clone the repository into ~/.bash_it:

    Terminal window
    git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it
  2. Run the installation script, which offers to back up your existing .bashrc before changing it:

    Terminal window
    ~/.bash_it/install.sh
  3. Turn bash-it on by hand if you declined the automatic change of .bashrc, by adding this line to it:

    Terminal window
    source ~/.bash_it/bash_it.sh
  4. Reload the configuration:

    Terminal window
    source ~/.bashrc

bash-it configuration

bash-it ships many modules, most of them turned off by default. The bash-it show command lists a catalogue with the state of each entry, and bash-it enable turns on the one you want.

Turn on and manage aliases

The alias sets turned on are stored in ~/.bash_it/aliases/enabled. bash-it show alias prints the catalogue, with [ ] for an inactive set and [x] for an active one:

Terminal window
bash-it show alias
Alias Enabled? Description
ag [ ] the silver searcher (ag) aliases
ansible [ ] ansible abbreviations
apt [ ] Apt and dpkg aliases for Ubuntu and Debian distros.
atom [ ] Atom.io editor abbreviations
bash-it [ ] Aliases for the bash-it command (these aliases are automatically included with the "general" aliases)
bolt [ ] puppet bolt aliases
bundler [ ] ruby bundler
bash-it enable alias ansible

The last command turns on the ansible alias set, which abbreviates common Ansible commands. The same principle applies to every set listed.

Turn on plugins

Plugins add functions and behaviours to the terminal. bash-it show plugins lists their catalogue; the base plugin, marked [x], is on by default:

Terminal window
bash-it show plugins
Plugin Enabled? Description
alias-completion [ ]
autojump [ ] Autojump configuration, see https://github.com/wting/autojump for more details
aws [ ] AWS helper functions
base [x] miscellaneous tools
...
bash-it enable plugin docker

This command turns on the Docker plugin, which provides helper functions and completions to manage your containers.

Turn on completions

Completions let Bash suggest the options and arguments of a command when you press Tab. To turn on the one for SSH:

Terminal window
bash-it enable completion ssh

The Tab key then completes the known host names after ssh, which makes typing your connections easier.

Customising themes

A bash-it theme replaces your PS1 with a richer prompt: user, machine, current directory, Git state, sometimes the time or the exit code. The available themes are the subfolders of ~/.bash_it/themes, each holding the .bash file that defines it.

Terminal window
ls ~/.bash_it/themes
90210 codeword font modern powerline-naked sexy
agnoster cooperkid gallifrey modern-t powerline-plain simple
atomic cupcake githelpers.theme.bash modern-time powerturk sirup
axin demula gitline morris primer slick
bakke dos hawaii50 n0qorg pro standard
barbuk doubletime inretio newin pure tonka
base.theme.bash doubletime_multiline iterate norbu purity tonotdo
binaryanomaly doubletime_multiline_pyonly kitsune nwinkler radek tylenol
bira dulcie lambda nwinkler_random_colors rainbowbrite wanelo
bobby duru liquidprompt oh-my-posh ramses zitron
bobby-python easy luan p4helpers.theme.bash rana zork
brainy elixr mairan parrot redline
brunton emperor mbriggs pete rjorgenson
candy envy metal powerline robbyrussell
clean essential minimal powerline-multiline roderik

Among the most used are powerline, bobby and pure. The theme is chosen with the BASH_IT_THEME variable of .bashrc, for example for powerline:

Terminal window
export BASH_IT_THEME='powerline'

Then reload your configuration so that the new theme replaces the current prompt:

Terminal window
source ~/.bashrc

Adapt the theme to your needs

Each theme is an editable .bash file in ~/.bash_it/themes. To add a piece of information to it, you write a function and inject it into the prompt. Example with the battery state, read by acpi when installed:

Terminal window
# Add a battery status segment
battery_status() {
if command -v acpi &> /dev/null; then
acpi -b | grep -o '[0-9]*%' | head -n 1
fi
}
export PS1='$(battery_status) '$PS1

The command -v acpi test avoids an error on machines without a battery or without the tool. Keep your changes in a copy of the theme: an update of bash-it through git pull would overwrite the original file.

Using fzf

fzf is an interactive filter on the command line: it shows a list and narrows it as you type, without requiring the exact name. Integrated into Bash, it replaces the Ctrl+R history search with a filterable list, and adds Ctrl+T to insert a file path.

Installing fzf

fzf is packaged on every reference distribution, but not in the same repositories nor in the same version, and the version decides how to turn it on. Measured: 0.60 on Debian 13, 0.44 on Ubuntu 24.04, and 0.58 from EPEL on AlmaLinux 10, where dnf install fzf fails without that repository.

  • Debian/Ubuntu:

    Terminal window
    sudo apt install fzf
  • RHEL and derivatives (the package comes from EPEL):

    Terminal window
    sudo dnf install epel-release
    sudo dnf install fzf
  • macOS with Homebrew (in French):

    Terminal window
    brew install fzf

Turn on the fzf plugin with bash-it

If you use bash-it, a dedicated plugin loads fzf for you. It assumes fzf is already installed by the package manager:

Terminal window
bash-it enable plugin fzf

Then reload .bashrc: the fzf shortcuts are active without touching the file yourself.

Add fzf to the .bashrc file

Without bash-it, turning it on takes a few lines of .bashrc, which depend on the installed version. Since fzf 0.48, the fzf --bash command itself produces the code of the shortcuts and of the completion: that is the case of Debian 13 and AlmaLinux 10. Ubuntu 24.04, with its version 0.44, does not know it: you must load the files provided by the package there.

Terminal window
# fzf 0.48 and later (Debian 13, AlmaLinux 10 with EPEL)
eval "$(fzf --bash)"
# older fzf (Ubuntu 24.04): files shipped by the package
source /usr/share/doc/fzf/examples/key-bindings.bash
source /usr/share/bash-completion/completions/fzf
# Appearance: 40 % height, list from top to bottom, border
export FZF_DEFAULT_OPTS="--height 40% --reverse --border"

Keep only the block that matches your system: fzf --version tells you which. The FZF_DEFAULT_OPTS variable, on the other hand, applies to every version.

Reload the configuration

After changing your .bashrc file, reload it, then try Ctrl+R: a filterable list of your history must open instead of the classic search.

Terminal window
source ~/.bashrc

Writing Bash scripts: automation and good practices

A Bash script is a file that chains commands, to automate a repetitive task. The "Write Bash scripts" module of this path covers it in detail; this section only recalls the basics, to show what your .bashrc has in common with a script.

A script starts with the shebang line, which tells the system which interpreter must run it:

#!/usr/bin/env bash
echo "Hello, this is a simple Bash script"

The arguments passed to the script arrive in $1, $2, and so on, which makes the script reusable with different values:

#!/usr/bin/env bash
user_name=$1
echo "Welcome, $user_name!"

The control structures if, for and while steer the execution according to the state of the system, for example the existence of a file:

#!/bin/bash
if [ -f "/etc/passwd" ]; then
echo "The file /etc/passwd exists."
else
echo "The file /etc/passwd does not exist."
fi

To run it directly, a script must be made executable, then started with its path:

Terminal window
chmod +x my_script.sh
./my_script.sh

Further in writing Bash scripts

Two lessons of the scripts module extend these basics. They come before this one in the path, and you can go back to them at any time:

Going further with Bash: tools and advanced customisation

Two tools often come on top of .bashrc when customisation reaches its limits. asdf (in French) is a version manager that installs several versions of the same language or tool side by side, and switches from one to the other depending on the project. direnv automatically loads and unloads environment variables according to the current directory, which avoids the forgotten export when you change project.

Combined with bash-it, these tools produce a working environment very close, in comfort, to what Zsh offers natively, without changing shell or relearning a syntax.

Troubleshooting

Almost every customisation problem comes from a file not reloaded or from a line that does not match your tool's version. The reflex: open a new terminal, which reads everything again from scratch.

SymptomLikely causeSolution
Changes to .bashrc do not applyThe file was not reloaded after the changeRun source ~/.bashrc or open a new terminal
The prompt shows odd characters, long lines wrap badlyPS1 colour codes not enclosedEnclose each colour code with \[ and \]
bash-it does not load the pluginsThe plugins are not turned onRun bash-it enable plugin <name> then source ~/.bashrc
unknown option: --bash when the terminal startsfzf older than 0.48 (Ubuntu 24.04)Load /usr/share/doc/fzf/examples/key-bindings.bash instead
Ctrl+R stays the classic searchfzf shortcuts not loadedAdd eval "$(fzf --bash)" or the key-bindings.bash file to .bashrc
dnf install fzf does not find the packagefzf comes from EPEL on RHEL and its derivativessudo dnf install epel-release, then run it again

Key points

  • The ~/.bashrc file is the central place to customise Bash, read by every interactive terminal, including login sessions through ~/.profile or ~/.bash_profile.
  • Aliases and functions in .bashrc automate repetitive commands.
  • The PS1 prompt can show user, host and directory; its colour codes are enclosed in \[ and \].
  • bash-it provides a complete, ready-to-use framework of themes and plugins.
  • fzf greatly improves history search; its version decides how to turn it on.

Knowledge check

Check that the essentials of this guide stuck. The questions cover only what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn