The environment variables lesson explained what .bashrc is. This lesson is about making the shell yours: shortcuts for commands you type fifty times a day, small functions that stitch commands together, a prompt that shows the information you actually need, and the startup-file rules that decide when each setting loads. A well-configured shell removes friction from every task that follows.
An alias substitutes one word for a longer command. It is expanded before the rest of the line is parsed, so any extra arguments are appended.
alias ll='ls -alF --color=auto'
alias la='ls -A'
alias ..='cd ..'
alias ...='cd ../..'
alias gs='git status'
alias gl='git log --oneline --graph --decorate -20'
alias ports='ss -tulpn'
alias please='sudo'
alias rm='rm -i' # safety net
alias grep='grep --color=auto'alias # list all aliases
alias ll # show one
unalias ll # remove
\ls # run the real command, bypassing an alias
type ll # "ll is aliased to `ls -alF --color=auto'"Aliases are stored in memory only; put them in ~/.bashrc (or a separate ~/.bash_aliases that .bashrc sources) to keep them between sessions. Use single quotes so nothing is expanded at definition time.
Aliases cannot use arguments in the middle of a command or contain logic. Shell functions can, and they live in the same file.
# make a directory and enter it
mkcd() {
mkdir -p "$1" && cd "$1"
}
# back up a file with a timestamp
bak() {
cp -v "$1" "$1.$(date +%Y%m%d-%H%M%S).bak"
}
# search running processes by name
psg() {
ps aux | grep -v grep | grep -i --color=auto "$1"
}
# universal extractor
extract() {
case "$1" in
*.tar.gz|*.tgz) tar xzf "$1" ;;
*.tar.xz) tar xJf "$1" ;;
*.zip) unzip "$1" ;;
*.gz) gunzip "$1" ;;
*) echo "extract: unknown archive type: $1" ;;
esac
}Inside a function $1, $2 and $@ are the arguments, exactly as in a script. Always quote them. A function defined in .bashrc is available in every interactive shell but not in scripts, which start clean.
The prompt is the value of PS1, re-evaluated before every line. Backslash escapes insert live information, and ANSI colour codes must be wrapped in \[ and \] so bash can measure the visible length correctly.
| Escape | Shows |
|---|---|
| \u | username |
| \h | hostname (short) |
| \w | current directory, with ~ for home |
| \W | basename of the current directory |
| \$ | $ for users, # for root |
| \t | time, 24-hour |
| \n | newline |
| \[\e[32m\] … \[\e[0m\] | start green … reset colour |
# Simple two-colour prompt
PS1='\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]\$ '
# With the current git branch
parse_git_branch() {
git branch 2>/dev/null | sed -n 's/^\* \(.*\)/ (\1)/p'
}
PS1='\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[33m\]$(parse_git_branch)\[\e[0m\]\$ '
# Two-line prompt: path on the first line, a clean second line for typing
PS1='\[\e[34m\]\w\[\e[0m\]\n\$ 'The $(parse_git_branch) inside single quotes is evaluated every time the prompt is drawn, which is what you want. Colour codes: 31 red, 32 green, 33 yellow, 34 blue, 35 magenta, 36 cyan; 1;32 for bold green.
Bash reads different files depending on how it was started, and this is the most common reason a customization "does not work".
| Shell type | Files read | Examples |
|---|---|---|
| Login shell | /etc/profile, then the first of ~/.bash_profile, ~/.bash_login, ~/.profile | SSH session, text console |
| Interactive non-login | /etc/bash.bashrc, ~/.bashrc | new terminal tab in a desktop |
| Non-interactive | only $BASH_ENV if set | scripts, cron |
The convention that makes everything work: put aliases, functions and PS1 in ~/.bashrc, and make sure ~/.profile (or ~/.bash_profile) sources it. Ubuntu's default ~/.profile already does. Environment variables such as PATH belong in ~/.profile so login shells and graphical sessions inherit them.
# ~/.bash_profile on systems that do not have this yet
[ -f ~/.bashrc ] && . ~/.bashrcAfter editing, run source ~/.bashrc (or . ~/.bashrc) to apply changes in the current shell.
shopt -s autocd # type a directory name to cd into it
shopt -s cdspell # correct minor typos in cd
shopt -s histappend # append history rather than overwrite on exit
shopt -s globstar # ** matches recursively: ls **/*.js
HISTSIZE=50000
HISTFILESIZE=100000
HISTCONTROL=ignoreboth # skip duplicates and lines starting with a space
export EDITOR=vim
set -o vi # vi-style line editing, if you prefer it$(...), which runs once at definition time instead of each use.ls() {...}), then losing access to the original. Use command ls inside the function.\[ \] around colour codes, which makes line editing jump and wrap incorrectly.PATH changes only in .bashrc, so GUI applications and cron do not see them.Why would you use a function instead of an alias?
~/.bashrc with single quotes.$1 and $@, and use command to call the original program.PS1 builds the prompt from escapes like \u, \h, \w; wrap colour codes in \[ \].~/.profile; interactive shells read ~/.bashrc; have the former source the latter.source ~/.bashrc applies edits immediately; shopt and HIST* variables tune behaviour further.Next lesson: Shell Scripting Basics — turn sequences of commands into reusable scripts with a shebang, variables and simple control flow.