.bashrc, Aliases and Functions: Set Up Your Bash Shell Properly
On this page
Sooner or later you will want Bash to remember things for you: a shorter way to type a long command, a nicer prompt, a directory added to your PATH. All of that goes into a startup file. The confusing part is that Bash has several, and which one runs depends on how the shell was started.
This guide clears that up, then covers aliases, functions, and a few defaults worth having.
.bashrc vs .bash_profile vs .profile
Bash distinguishes two kinds of interactive shell:
- A login shell is the first shell of a session: logging in on a text console, connecting with
ssh, or runningbash --login. On macOS, Terminal opens a login shell for every new window. - A non-login interactive shell is any other shell you type into, such as a new terminal tab in most Linux desktops, or running
bashinside an existing shell.
They read different files:
| Shell type | Files Bash reads |
|---|---|
| Login shell | /etc/profile, then the first one that exists of ~/.bash_profile, ~/.bash_login, ~/.profile |
| Non-login interactive shell | ~/.bashrc (Debian and Ubuntu also read /etc/bash.bashrc first) |
| Script (non-interactive) | None of the above |
Notice that a login shell does not read ~/.bashrc by itself. That is why an alias can work in your desktop terminal but not over SSH. The usual fix is to keep everything interactive in ~/.bashrc and have the login file load it. Debian and Ubuntu's default ~/.profile already does this. If you have a ~/.bash_profile, make sure it contains:
# ~/.bash_profile
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
~/.bash_profile on a system that relied on ~/.profile stops ~/.profile from being read, because Bash only reads the first file it finds. If your PATH changes vanish after you create one, that is why; source ~/.profile from it too.A simple rule of thumb: environment variables such as PATH and EDITOR go in ~/.profile (or ~/.bash_profile). Aliases, functions, prompt settings and shell options go in ~/.bashrc. To check what kind of shell you are in:
$ shopt -q login_shell && echo login || echo non-login
non-login
The details are in the Bash Startup Files section of the manual.
Reloading after a change
Edits to ~/.bashrc only take effect in new shells. To apply them to the current one, read the file into it with source (or its short form, a single dot):
$ source ~/.bashrc
$ . ~/.bashrc
Sourcing adds to what is already defined, so an alias you deleted from the file is still active until you run unalias or start a fresh shell. For a clean slate, exec bash replaces the current shell with a new one.
Aliases
An alias is a short name that Bash replaces with longer text when it is the first word of a command:
alias ll='ls -alF'
alias la='ls -A'
alias ..='cd ..'
alias ...='cd ../..'
alias grep='grep --color=auto'
alias df='df -h'
alias du1='du -h -d 1'
alias ports='ss -tulpn'
Use single quotes so nothing in the alias is expanded when it is defined. A few commands help you manage aliases:
$ alias # list all aliases
$ type ll # show what a name really runs
ll is aliased to `ls -alF'
$ unalias ll # remove an alias from this shell
$ \ls # run the real ls, skipping any alias
$ command ls # same idea, also skips functions
Debian and Ubuntu's default ~/.bashrc loads ~/.bash_aliases if it exists, so you can keep aliases in their own file.
shopt -s expand_aliases, so do not rely on your aliases in scripts; write the full command or use a function.When to use a function instead
An alias is plain text substitution. It cannot take an argument in the middle, make decisions, or run several steps cleanly. As soon as you need any of that, write a function. Functions go in ~/.bashrc too.
Make a directory and change into it:
mkcd() {
mkdir -p -- "$1" && cd -- "$1"
}
Extract almost any archive:
extract() {
if [ ! -f "$1" ]; then
echo "extract: '$1' is not a file" >&2
return 1
fi
case "$1" in
*.tar.gz|*.tgz) tar -xzf "$1" ;;
*.tar.bz2|*.tbz2) tar -xjf "$1" ;;
*.tar.xz) tar -xJf "$1" ;;
*.tar) tar -xf "$1" ;;
*.zip) unzip "$1" ;;
*.gz) gunzip "$1" ;;
*) echo "extract: unknown type: $1" >&2; return 1 ;;
esac
}
Search your history for a word:
hgrep() {
history | grep -i -- "$*"
}
A few things to know about functions:
- Inside a function,
$1,$2and"$@"are the function's own arguments, just like in a script. The scripting basics guide explains quoting them. - Use
return, notexit. Because functions run in your current shell,exitwould close your terminal. - Declare temporary variables with
localso they do not leak into your shell. - A function can change your shell's state, such as the current directory. A script cannot, which is why
mkcdmust be a function. type mkcdprints a function's definition, andunset -f mkcdremoves it.
Safe defaults, and the rm -i debate
Many setups include these aliases to ask before overwriting or deleting:
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
They help, but know their limits:
rm -rfstill deletes without asking, because a later-foverrides the alias's-i.- You get used to the safety net, then type
rm *on a server or in a script where the alias does not exist. - Answering
yto fifty prompts trains you to stop reading them.
With GNU coreutils (standard on Linux), rm -I is a better compromise. It asks once when you remove more than three files or delete recursively, and stays quiet otherwise:
alias rm='rm -I'
macOS's rm also accepts -I. The real safety net is still backups and a habit of running ls with the same pattern before you run rm.
Other good things to put in .bashrc
# Correct small typos in cd arguments
shopt -s cdspell
# Let ** match files in all subdirectories
shopt -s globstar
# Update LINES and COLUMNS after each command, for resized windows
shopt -s checkwinsize
# Your preferred editor for git, crontab and Ctrl+X Ctrl+E
export EDITOR=nano
History settings deserve their own section; see the history guide. For the prompt, see how to customize your Bash prompt.
A small PATH addition, in ~/.profile so it applies to the whole login session:
export PATH="$HOME/bin:$PATH"
~/.bashrc prints errors in every new shell, and a broken PATH line can make basic commands "disappear". Fix it from the shell that is still working, or run /bin/nano ~/.bashrc with the full path.Quick reference
| Task | Command or file |
|---|---|
| Interactive settings, aliases, functions | ~/.bashrc |
| Environment variables, PATH | ~/.profile or ~/.bash_profile |
| Load .bashrc in login shells | . ~/.bashrc inside ~/.bash_profile |
| Apply changes now | source ~/.bashrc |
| List aliases | alias |
| See what a name runs | type name |
| Skip an alias once | \name or command name |
| Remove an alias / function | unalias name / unset -f name |