How to Customise Your Linux Shell (Aliases, a Better Prompt, History That Works and Zsh or Fish)

A terminal that works for you: aliases, a prompt that says which server you're on, history that never forgets, and safer defaults.

You type docker compose logs -f forty times a week. Your prompt looks the same on the server and the Pi, which is how rm -r happens on the wrong box. Ctrl + R can't find the command you ran last Tuesday because another window overwrote the history. Twenty lines in ~/.bashrc fix all three, and they travel to every machine with the Ansible baseline (139).

Quick reference

WantWhere
Aliases and functions~/.bash_aliases (sourced by Ubuntu's .bashrc)
A prompt with host, folder, git branchPS1 in .bashrc, or Starship
History across sessions, no duplicates, with timestampsHISTSIZE, HISTCONTROL, shopt -s histappend
Safer rm, cp, mvalias rm='rm -I' etc.
A better shellZsh + Oh My Zsh, or Fish
Applysource ~/.bashrc

1. Aliases

nano ~/.bash_aliases

# navigation and listing
alias ll='ls -alFh --color=auto'
alias ..='cd ..'
alias ...='cd ../..'

# safety
alias rm='rm -I'
alias cp='cp -i'
alias mv='mv -i'

# docker
alias dc='docker compose'
alias dcl='docker compose logs -f --tail 100'
alias dcu='docker compose up -d'
alias dcd='docker compose down'
alias dps='docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"'

# system
alias update='sudo apt update && sudo apt upgrade -y && sudo apt autoremove -y'
alias ports='sudo ss -tlnp'
alias disk='df -h | grep -v tmpfs'
alias jl='journalctl -u'
alias check='uptime; systemctl --failed; df -h | grep -v tmpfs; free -h; docker ps --format "{{.Names}}\t{{.Status}}"'

# functions take arguments
mkcd() { mkdir -p "$1" && cd "$1"; }
extract() { case "$1" in *.tar.gz|*.tgz) tar xzf "$1";; *.zip) unzip "$1";; *.tar.xz) tar xJf "$1";; *) echo "unknown";; esac; }

source ~/.bashrc. dcl in any compose folder tails that stack; check is tutorial 80's five-minute version. rm -I asks once before deleting more than three files or a folder — enough to catch a typo, not enough to annoy.

2. A prompt that tells you where you are

Append to ~/.bashrc:

parse_git_branch() { git branch 2>/dev/null | sed -n 's/^\* //p' | sed 's/^/ (/;s/$/)/'; }
if [ "$(id -u)" -eq 0 ]; then C='\[\e[1;31m\]'; else C='\[\e[1;32m\]'; fi
PS1="${C}\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[1;33m\]\$(parse_git_branch)\[\e[0m\]\$ "

Green john@homeserver, blue folder, yellow git branch; the name turns red when you're root. Give each machine a distinct hostname (tutorial 9) and a different colour in C if you like — the Pi in cyan, the VPS in magenta. You stop running things on the wrong box.

For a prettier, faster, cross-shell prompt: curl -sS https://starship.rs/install.sh | sh, then eval "$(starship init bash)" in .bashrc. It shows git status, Docker context, and command duration out of the box.

3. History that actually works

HISTSIZE=100000
HISTFILESIZE=200000
HISTCONTROL=ignoreboth:erasedups
HISTTIMEFORMAT='%F %T '
shopt -s histappend
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"

Every session appends instead of overwriting, duplicates collapse, timestamps show when you ran something, and Ctrl + R reaches back a hundred thousand commands. history | grep certbot becomes a reliable record of what you did last year.

4. Small defaults worth setting

shopt -s autocd # type a folder name to cd into it
shopt -s cdspell # fix minor typos in cd
export EDITOR=nano # what sudoedit, git and crontab -e open
set -o noclobber # > won't overwrite an existing file (use >| to force)

And sudo visudo → Defaults timestamp_timeout=30 so sudo asks every 30 minutes instead of 15.

5. Zsh or Fish?

For a server you mostly SSH into, well-configured bash is fine and is what every tutorial assumes. Try Zsh on your laptop first; if you like it, bring it to the server. Keep /bin/bash for root and scripts either way.

6. Take it everywhere

Put .bashrc, .bash_aliases and .tmux.conf in a dotfiles repo on Gitea (45), and have the Ansible base role (140) copy them to every host. A new machine then feels like home at the first prompt.

Troubleshooting

Aliases don't work in scripts or cron. Correct — aliases are interactive only. Use full commands or functions in scripts.

Prompt shows raw escape codes. Missing [ and ] around colour sequences; copy the line exactly.

History still missing commands. histappend not set, or two shells started before the change; new sessions behave.

rm -I not asking. Fewer than four files; that's by design. Use rm -i for always.

Wrapping up

A .bash_aliases with the commands you actually type, a prompt that names the host and turns red as root, history that keeps everything, three safer defaults. Twenty minutes, then the same file on every machine via git and Ansible — and the terminal stops costing you keystrokes and mistakes.

Call us