.bashrc, Aliases and Functions: Set Up Your Bash Shell Properly

Basics · 7 min read · Updated 25 Oct 2026

On this page
  1. .bashrc vs .bash_profile vs .profile
  2. Reloading after a change
  3. Aliases
  4. When to use a function instead
  5. Safe defaults, and the rm -i debate
  6. Other good things to put in .bashrc
  7. Quick reference

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 running bash --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 bash inside an existing shell.

They read different files:

Shell typeFiles 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
Creating a ~/.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.

Aliases only work in interactive shells. Inside a script they are ignored unless the script runs 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, $2 and "$@" are the function's own arguments, just like in a script. The scripting basics guide explains quoting them.
  • Use return, not exit. Because functions run in your current shell, exit would close your terminal.
  • Declare temporary variables with local so 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 mkcd must be a function.
  • type mkcd prints a function's definition, and unset -f mkcd removes 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 -rf still deletes without asking, because a later -f overrides 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 y to 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"
Keep a working terminal open when you edit startup files. A syntax error in ~/.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

TaskCommand 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 nowsource ~/.bashrc
List aliasesalias
See what a name runstype name
Skip an alias once\name or command name
Remove an alias / functionunalias name / unset -f name