Linux Tutorials

How To Customize Bash on Linux with Bash-it

The default Bash-it install made a new interactive shell 13 times slower on our test server. You pay for its prompts, aliases and completions every time a shell starts. Plain Bash started in 31 ms, Bash-it took 410 ms, and after we enabled the git aliases, the git and history plugins and the git and ssh completions it took 1.1 seconds. One bundled completion caused almost all of it, and turning it off brought startup back under 100 ms.

Original content from computingforgeeks.com - post 16749

This guide shows you how to customize Bash on Linux with Bash-it: install it, pick a theme, enable aliases, plugins and completions, check the setup with bash-it doctor, then update or remove it cleanly. It also covers a login-shell side effect and an uninstall leftover. Everything was tested on Ubuntu 26.04 in October 2026 with Bash 5.3 and Bash-it from the master branch at commit ee8396b.

Install Bash-it

Bash-it is a set of shell scripts in a git repository, so there is no package to install and nothing runs as root. It lives in your home directory and loads from ~/.bashrc, which means each user who wants it installs their own copy. You need:

  • Bash 3.2 or newer, though a few plugins need Bash 4 or newer (Ubuntu 26.04 ships 5.3)
  • git, to clone the repository and to run bash-it update later
  • A UTF-8 locale, because many themes print symbols such as ± and ✗

git was already on our Ubuntu 26.04 image. If git --version fails, install it with sudo apt install git on Ubuntu or Debian, or sudo dnf install git on Fedora and the RHEL family. Then clone Bash-it into ~/.bash_it, the path the installer and docs expect:

git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it

Run the installer next. Without a flag it asks whether to keep your .bashrc and append the Bash-it template, or replace the file with the template. Keep it, because your existing aliases and PATH changes live there, and --append-to-config answers that question up front:

~/.bash_it/install.sh --append-to-config

The installer backs up your .bashrc to .bashrc.bak, appends its template and enables a small default profile. That backup is your way back if you ever need to undo the install by hand.

Installing bash-it
Your original .bashrc has been backed up to .bashrc.bak
Bash-it template has been added to your .bashrc

Trying to parse profile 'default'...
Profile 'default' parsed successfully!
Disabling current configuration...
all plugins disabled.
all aliases disabled.
all completions disabled.

Enabling configuration based on profile...
base enabled with priority 250.
aliases enabled with priority 800.
bash-it enabled with priority 350.
system enabled with priority 325.
general enabled with priority 750.
bash-it enabled with priority 750.
directory enabled with priority 750.
editor enabled with priority 750.

Profile 'default' enabled!

Installation finished successfully! Enjoy bash-it!
To start using it, open a new tab or 'source ~/.bashrc'.

To show the available aliases/completions/plugins, type one of the following:
  bash-it show aliases
  bash-it show completions
  bash-it show plugins

To avoid issues and to keep your shell lean, please enable only features you really want to use.
Enabling everything can lead to issues.

Start a new shell, or run source ~/.bashrc, and the prompt switches to the default bobby theme. The installer takes a few other flags that are useful when you script the setup across machines:

  • --silent: no prompts and the default profile, but it replaces .bashrc with the template unless you add --append-to-config
  • --interactive: asks about each alias, plugin and completion
  • --no-modify-config: leaves .bashrc alone and creates no ~/.bash_profile, for when you load Bash-it yourself
  • --overwrite-backup (-f): replaces an existing .bashrc.bak; without it a silent re-install aborts when that backup exists

For a fleet, --silent --append-to-config gives every host the same lean default profile, and you then enable components per host with the commands below. That keeps the slow parts off servers where nobody needs them.

Fix the login shell PATH after installing

On Ubuntu and Debian you should delete the ~/.bash_profile the installer creates, unless you wrote one yourself. When that file does not exist, the installer writes a three-line version whose only job is to source .bashrc. The install docs do recommend sourcing .bashrc from .bash_profile, but they don’t mention what that does to ~/.profile. It does this even when ~/.profile exists, and Bash reads ~/.bash_profile instead of ~/.profile for login shells, so everything in ~/.profile stops running. On Ubuntu that file is what puts ~/.local/bin on your PATH, which is where pipx, uv and pip install --user put their commands.

We confirmed it on the lab VM. A login shell with the new .bash_profile had lost ~/.local/bin:

login PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Ubuntu’s own ~/.profile already sources ~/.bashrc, so the extra file adds nothing there. Check what the installer wrote before you delete it, so you don’t remove something of your own:

cat ~/.bash_profile

If it shows only these three lines, it is the installer’s file and safe to remove. Anything more means you or another tool wrote it, so merge your lines into ~/.profile first.

if [[ $- == *i* && -s ~/.bashrc ]]; then
	source ~/.bashrc
fi

Remove it, then start a login shell and confirm both the PATH and Bash-it came back. The -l flag makes Bash read the login files, which is what an SSH session does.

rm ~/.bash_profile
bash -lic 'echo PATH=$PATH; echo BASH_IT=$BASH_IT theme=$BASH_IT_THEME'

Your ~/.local/bin leads the PATH again. Bash-it still loads, because ~/.profile sources .bashrc for you.

PATH=/home/josphat/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
BASH_IT=/home/josphat/.bash_it theme=bobby

Ubuntu only adds ~/.local/bin when the directory exists, so a brand new account may not show it either way. On a distro without a ~/.profile, keep the installer’s file, because it is then the only thing that loads Bash-it in a login shell. The Bash startup files section of the manual lists the order Bash reads these files in.

Check the setup with bash-it doctor

bash-it doctor is the first thing to run after an install or when something looks wrong, because it shows in one screen which config file loads Bash-it, how far your clone is from upstream and which components are on. The maintainers ask for its output in every bug report:

bash-it doctor

The parts worth reading are the version status and the component list at the end. Between them the report prints the Bash-it lines from .bashrc with line numbers and a profile check, which we’ve trimmed here:

Bash-it Doctor Summary
======================

## Environment
OS: Linux 7.0.0-15-generic
Bash Version: 5.3.9(1)-release
Bash-it Location: /home/josphat/.bash_it
Config File: /home/josphat/.bashrc

## Bash-it Version
Current Commit: ee8396b
Status: Up to date with origin/master ✓

## Enabled Components
Aliases (4): bash-it directory editor general
Plugins (1): base
Completions (3): aliases bash-it system

That is the whole default profile: four alias groups, one plugin and three completions. Keep it in mind when you add more, because the completion named aliases in that list is the one that costs the most at startup.

Enable aliases

Bash-it groups its components into aliases, plugins and completions, and nothing outside the default profile is enabled until you ask for it. That is deliberate, since loading everything slows every new shell and pulls in helpers for tools you don’t have. bash-it show listed 52 alias groups, 83 plugins and 92 completions on our checkout. See the alias groups and which ones are on:

bash-it show aliases

An [x] marks an enabled group, and the description column says what each group is for. The first rows of the list look like this.

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              [x]        Aliases for the bash-it command (these aliases are automatically included with the "general" aliases)
bolt                 [ ]        puppet bolt aliases
bundler              [ ]        ruby bundler
clipboard            [ ]        xclip shortcuts
composer             [ ]        common composer abbreviations
curl                 [ ]        Curl aliases for convenience.
directory            [x]        Shortcuts for directory commands: ls, cd, &c.

Enable groups by name. Several names fit in one command, which saves a shell reload between them.

bash-it enable alias git apt

Each group reports the load priority it got. Bash-it loads components in that order, lowest number first.

git enabled with priority 750.
apt enabled with priority 750.

Read what a group defines before you rely on it, because the short names collide with habits from other shells. bash-it help aliases git prints every alias in the group:

g='git'
get='git'
got='git'
ga='git add'
gall='git add -A'
gap='git add -p'
gav='git add -v'
gb='git branch'
gba='git branch --all'
gbd='git branch -d'
gbD='git branch -D'
gbl='git branch --list'
gbla='git branch --list --all'
gblr='git branch --list --remotes'
gbm='git branch --move'
gbr='git branch --remotes'
gbt='git branch --track'
gbc='git for-each-ref --format="%(authorname) %09 %(if)%(HEAD)%(then)*%(else)%(refname:short)%(end) %09 %(creatordate)" refs/remotes/ --sort=authorname DESC' # FROM https://stackoverflow.com/a/58623139/10362396'
gc='git commit -v'
gca='git commit -v -a'

Check the ones you’ll type most in a new shell, since a wrong guess here costs you work. alias with names prints each definition.

alias gs gst gl ga

Here gst is git stash, not git status. If you’re coming from Zsh with Oh My Zsh, where gst shows the status, that one will stash your work when you meant to look at it:

alias gs='git status'
alias gst='git stash'
alias gl='git pull'
alias ga='git add'

Turn a group off the same way with bash-it disable alias apt. The change applies to new shells, so open one or run source ~/.bashrc before you test it.

Enable plugins and completions

Plugins add shell functions and environment setup, and completions add tab completion for commands Bash doesn’t complete on its own. The commands follow the same pattern as aliases, so bash-it show plugins and bash-it show completions list what is available. We added the git and history plugins:

bash-it enable plugin git history

Plugins load earlier than aliases, which is why their priority number is lower. The number is the prefix of the symlink Bash-it creates in ~/.bash_it/enabled.

git enabled with priority 250.
history enabled with priority 250.

Completions work the same way. We enabled the ones for git and ssh:

bash-it enable completion git ssh

Both report priority 350, which places them between plugins and aliases in the load order. The default system completion already loads your distro’s bash-completion package, so add these only when you want Bash-it’s versions on top.

git enabled with priority 350.
ssh enabled with priority 350.

Resist bash-it enable plugin all. The installer itself warns that enabling everything can cause issues, and each component adds to the time every new shell takes to start. The numbers in the last section show how fast that adds up.

bash-it search is quicker than scrolling three lists, because it searches aliases, plugins and completions at once and shows enabled matches in green. Pass one or more terms:

bash-it search docker

The results come back grouped by component type, so you can see at once whether a tool has aliases, a plugin, a completion or all three. Docker has all three.

      aliases: docker docker-compose
      plugins: boot2docker docker docker-compose docker-machine
  completions: docker docker-compose docker-machine 

Prefix a term with a minus sign to exclude it. bash-it search python -pyenv returned only the python plugin on our install. Adding --enable or --disable to a search switches every match on or off, which is handy for a narrow term and risky for a broad one such as git, which matched 14 components across all three types.

Customize the Bash prompt with a theme

The theme is one variable, BASH_IT_THEME, in the Bash-it block of your ~/.bashrc, and the default is bobby. Our checkout had 84 theme directories under ~/.bash_it/themes, well past the “50+” the docs mention. List them:

ls ~/.bash_it/themes

Switch by rewriting that line. Replace atomic with any directory name from the list, or set the value to an empty string to turn theming off:

sed -i "s/^export BASH_IT_THEME=.*/export BASH_IT_THEME='atomic'/" ~/.bashrc
grep '^export BASH_IT_THEME' ~/.bashrc

The grep shows the new value. The running shell keeps its old prompt, so the theme takes effect in the next shell you start.

export BASH_IT_THEME='atomic'

We captured three themes from real prompts on the lab VM, inside a git repository with one modified and one untracked file, so you can see how each one reports git state. The default bobby puts the date, host and path on one line and the git summary on the next. On a VM it prints no% where a laptop would show the battery charge:

Bash-it bobby theme prompt showing git status on Ubuntu 26.04

atomic draws a two-line frame with user, host, path, git state and the time, which works well in a wide terminal. The second line holds only the cursor, so long commands get the full width.

Bash-it atomic theme two-line prompt on Ubuntu 26.04

powerline-plain keeps user, branch, git counts and path on one line, which suits narrow tmux panes. It drops the hostname, so it’s a poor choice when you hop between servers.

Bash-it powerline-plain theme prompt with git branch on Ubuntu 26.04

Not every theme works cleanly. The modern theme printed bash: python_venv: parameter not set before every prompt on our install, so pick another one if you see that line. If a prompt shows boxes instead of symbols, set a UTF-8 locale such as LC_ALL=en_US.UTF-8 and use a terminal font that has the glyphs. Our terminal emulator benchmarks help with that choice, and if you would rather have one prompt across Bash, Zsh and Fish, Starship does that job.

Update Bash-it without rolling back

Run bash-it update dev if you installed from the master branch as shown above. A plain bash-it update means “latest stable release”, and the latest tag, v3.2.0, is a year older than master, which was 99 commits ahead of it when we tested. On a full clone Bash-it notices that and warns you before it does anything. We cloned without --depth=1 to check, and answered n at the prompt:

Your version is a more recent development version (ee8396b5)
You can continue in order to revert and update to the latest stable version

Would you like to update to v3.2.0(0f04edce)? [Y/n] n
Not updating…

Between the warning and the prompt it lists the 71 non-merge commits you would lose. The --depth=1 clone from the install step is the dangerous case, because Bash-it cannot see that master already contains v3.2.0. On ours it skipped the warning, listed 3,107 commits as if they were an upgrade, and asked the same question. Enter means yes, so accepting the default moved our install back to v3.2.0 and reported success:

Bash-it successfully updated.

Migrating your installation to the latest stable version now...

All done, enjoy!

Check which channel you’re on with bash-it version after any update you’re unsure about.

bash-it version

After that accidental downgrade, the version type had changed to stable and the tag was a year old. Nothing else on screen hinted at it.

Version type: stable
Current tag: v3.2.0
Tag information: https://github.com/Bash-it/bash-it/releases/tag/v3.2.0
Compare to latest: https://github.com/Bash-it/bash-it/compare/v3.2.0...master

Pick a channel and stay on it. Stable releases are rare, so fixes reach master long before they reach a release. Move back to master with the dev channel:

bash-it update dev

Running bash-it version again shows the dev channel and the latest master commit. Future runs of bash-it update dev keep you there.

Version type: dev
Current git SHA: ee8396b5 on 2026-10-12T19:30:29+03:00
Commit info: https://github.com/Bash-it/bash-it/commit/ee8396b5
Compare to latest: https://github.com/Bash-it/bash-it/compare/ee8396b5...master

Your enabled components, theme and .bashrc survived both moves. To update from a script or cron job, put --silent after the channel, because bash-it update --silent on its own fails with “oops! –silent is not a valid option!”. The command also has to run in an interactive shell, since bash-it is a shell function that only .bashrc defines; plain bash -c and even bash -lc answered “bash-it: command not found” on our VM. We ran this crontab line’s command from /bin/sh with an empty environment and no terminal, the way cron starts it:

15 4 * * 0 bash -ic 'bash-it update dev --silent' >> "$HOME/bash-it-update.log" 2>&1

The log then held the update result plus two lines that every bash -i without a terminal prints, “cannot set terminal process group” and “no job control in this shell”. They are harmless, and sending output to a log keeps cron from mailing them to you every week:

bash: cannot set terminal process group (75407): Inappropriate ioctl for device
bash: no job control in this shell
Bash-it is up to date, nothing to do!

Add the line with crontab -e as your own user, not root, since Bash-it lives in your home directory. We only exercised the case where master was already current; an update that actually pulls commits also restarts the shell at the end, which we did not run unattended, so check the log after the first real update.

Uninstall Bash-it

Uninstalling restores the .bashrc you had before, but it leaves two things behind that you have to remove yourself. Run the bundled script from the Bash-it directory:

cd ~/.bash_it
./uninstall.sh

It keeps a copy of your current .bashrc in case you changed it after installing, so nothing you added is lost. Copy any lines you want to keep from that file before you delete it.

Current ~/.bashrc backed up to ~/.bashrc.pre-uninstall.bak
Your original ~/.bashrc has been restored.
NOTE: If you had made changes since installing Bash-it, they are preserved in ~/.bashrc.pre-uninstall.bak

Uninstallation finished successfully! Sorry to see you go!

Final steps to complete the uninstallation:
	-> Remove the ~/.bash_it folder
	-> Open a new shell/tab/terminal

On our VM the restored .bashrc was byte-identical to /etc/skel/.bashrc, so the restore is exact. The ~/.bash_profile from the install was still there, though, and it keeps hiding ~/.profile from login shells after Bash-it is gone. Remove the repository and the uninstaller’s backup first, since those are always safe to delete.

cd ~
rm -rf ~/.bash_it ~/.bashrc.pre-uninstall.bak
cat ~/.bash_profile

Then deal with ~/.bash_profile. If cat says there is no such file, you already removed it in the PATH fix above, and there is nothing to do. If it prints exactly the installer’s three lines, delete it with rm ~/.bash_profile. If it holds anything else, leave it alone: Fedora and the RHEL family ship their own .bash_profile in /etc/skel, and the installer never touches a file that already exists. Open a new shell and the plain prompt is back.

Speed up Bash-it startup

Disable the aliases completion and Bash-it costs you about 60 ms per shell instead of 380 ms or more. That completion adds tab completion to every alias, and it rebuilds that on every shell start, so its cost grows with each alias group you enable. On our 2 vCPU VM it was the difference between a terminal that opens instantly and one that lags a second behind every new tab, tmux pane or ssh login.

We measured with a small script that starts ten interactive shells after two warm-up runs and prints the median. Save it as ~/startup-bench.sh:

vim ~/startup-bench.sh

Paste this in. It is the exact file we used for every number below, so your results compare directly with ours.

#!/bin/bash
# median and mean of 10 interactive bash startups (ms), after 2 warm-ups
bash -i -c exit >/dev/null 2>&1; bash -i -c exit >/dev/null 2>&1
t=()
for i in $(seq 1 10); do
  s=$(date +%s%N); bash -i -c exit >/dev/null 2>&1; e=$(date +%s%N)
  t+=($(( (e-s)/1000000 )))
done
printf '%s\n' "${t[@]}" | sort -n | awk '{a[NR]=$1; s+=$1} END {printf "runs(ms): "; for(i=1;i<=NR;i++) printf a[i]" "; printf "\nmin=%d median=%.1f mean=%.1f max=%d\n", a[1], (a[5]+a[6])/2, s/NR, a[NR]}'

Run it with bash ~/startup-bench.sh before and after each change. These are the medians we got on Ubuntu 26.04:

ConfigurationMedian startupvs plain Bash
Plain Bash, Ubuntu default .bashrc31 ms1x
Bash-it default profile410 ms13x
Default profile, aliases completion off93 ms3x
Same, theme off as well85 ms2.7x
Plus git aliases, git and history plugins, git and ssh completions, aliases completion on1,108 ms36x
Same set, aliases completion off95 ms3x

Two rows tell the story. Adding the git alias group with aliases completion on pushed startup from 410 ms to over a second, while the same set with it off cost only 2 ms more than the default profile with it off. The theme itself is cheap at about 8 ms, so keep the prompt you like. Turn the expensive completion off:

bash-it disable completion aliases

Here are the before and after runs from our lab, with the git aliases, the git and history plugins and the git and ssh completions enabled. The spread between fastest and slowest run stayed within 40 ms, so the gap is not noise.

Bash-it shell startup time with and without aliases completion on Ubuntu 26.04

What you lose is completion after an alias. The aliases completion wraps each alias in the completion function of the command behind it, so gco borrows git’s branch completion; with it off, only the full git checkout completes. That’s a trade we’d take on any machine where you open shells often.

Keep Bash-it if you want a curated alias set and themes without writing them yourself. Skip it if all you want is a nicer prompt, which Starship gives you at a fraction of the load.

Once your shell is set up, the scripts you run in it matter more than the prompt. The Bash scripting books we recommend teach the language itself, and our bash backup script is a tested example to learn from. A customized tmux setup pairs well with a fast prompt. If you’re still deciding on a shell, the Bash, Zsh and Fish comparison lays out the differences.

Keep reading

Install GitHub CLI (gh) on Linux, macOS, and Windows Programming Install GitHub CLI (gh) on Linux, macOS, and Windows Install Sway on Fedora 45 / 44 with Waybar Desktop Install Sway on Fedora 45 / 44 with Waybar Check version of Installed Package on Ubuntu / Debian Debian Check version of Installed Package on Ubuntu / Debian Best Monitor Arms for a Multi-Monitor Developer Desk Programming Best Monitor Arms for a Multi-Monitor Developer Desk Best Mouse and Keyboard for Programming Programming Best Mouse and Keyboard for Programming Git Feature Branch Workflow – Develop Without Affecting Main Programming Git Feature Branch Workflow – Develop Without Affecting Main

Leave a Comment

Press ESC to close