| |

LFCS 46 🐧 Shell Aliases

⏱️ Estimated read: 11 min | |

A shell alias is a name that the shell substitutes for a command before executing it. When you type ll, the shell replaces it with ls -alF and runs the result. The mechanism is simple, but the rules around it are not: aliases are expanded only when the shell reads a line, only for interactive shells by default, and only when the alias name appears in the position where a command name is expected . For the LFCS exam, “Manage template user environment” and “Use shell/environment variables” are the relevant objectives, and aliases are part of the configuration that goes into a user’s shell startup files .

The distinction between an alias and a function is the one that matters most in practice. An alias is a literal text substitution—it cannot take arguments, cannot contain logic, and cannot be called with sudo in the way a user might expect . A function is a named block of shell code that receives arguments, can contain loops and conditionals, and can be exported to child processes . The Bash manual states that “for almost every purpose, shell functions are preferable to aliases” . Understanding when an alias is sufficient and when a function is necessary is the core of this topic.

Key point: An alias is a text substitution for a command name, created with alias name='command' and removed with unalias; it is expanded only in interactive shells unless shopt -s expand_aliases is set, it cannot take arguments, and it belongs in ~/.bashrc for persistence, not in ~/.profile.


Why aliases work the way they do

The expansion timing problem. Aliases are expanded when the shell reads a line, not when it executes it. If you define an alias on the same line as a command that uses it, the alias does not take effect until the next line is read. This is why the Bash manual warns to always put alias definitions on a separate line and never use alias in compound commands . The shell reads at least one complete line before executing any of the commands on it, and the alias expansion happens during that read.

The interactive-only problem. Aliases are not expanded in non-interactive shells unless the expand_aliases shell option is enabled with shopt -s expand_aliases. This means a script that defines an alias and then uses it on the next line will fail unless the option is set or the script sources the file that defines the alias . The reason is that non-interactive shells prioritize predictability and performance; alias expansion is a convenience for interactive use.

The argument problem. An alias cannot take arguments. If you define alias ll='ls -l' and then run ll /tmp, the shell expands it to ls -l /tmp, which happens to work because the argument is appended to the end. But alias greet='echo Hello' followed by greet World produces Hello World, not Hello, World as a function might format it. The alias value is a fixed string; the argument is simply appended. For any command that needs to position arguments, validate them, or use them in logic, a function is required .

The sudo problem. Aliases are not inherited by sudo. Running sudo ll does not work because sudo executes the command directly, and the alias expansion happened in the shell that invoked sudo, not in the sudo process. The alias is expanded to ls -alF before sudo runs, so sudo ls -alF works, but sudo ll fails because the alias was never expanded . This is a common source of confusion.


a. Creating, listing, and removing aliases

The alias builtin creates an alias when given a name and value, and lists all defined aliases when given no arguments. The unalias builtin removes one alias by name or all aliases with -a.

# Create a temporary alias for the current shell session
alias ll='ls -alF'

# Create an alias that adds color to grep output
alias grep='grep --color=auto'

# List all defined aliases
alias

# List a specific alias
alias ll

# Remove one alias
unalias ll

# Remove all aliases
unalias -a

The value must be quoted if it contains spaces. Single quotes are the safer choice because they prevent the shell from expanding variables or command substitutions in the alias value at definition time. The alias takes effect immediately for subsequent lines in the same shell session, but it is not persistent—closing the terminal and opening a new one loses it.


b. Persisting aliases in shell configuration files

Aliases belong in ~/.bashrc. The reason is the shell type distinction: ~/.bashrc is read by interactive non-login shells (the terminal you open in a graphical session), and it is the file that login shells source when the bridge is configured. Putting aliases in ~/.profile does not work for interactive non-login shells, because .profile is only read by login shells .

# ~/.bashrc

# Navigation shortcuts
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

# Safety nets
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Git shortcuts
alias gs='git status'
alias gc='git commit'
alias gp='git push'

The safety aliases (rm -i, cp -i, mv -i) are the classic example of an alias that changes behavior without changing the command name. They are not a substitute for careful typing, but they add a confirmation prompt that catches accidental deletions.

For login shells to see the aliases, ~/.bash_profile or ~/.profile must source ~/.bashrc:

# ~/.bash_profile or ~/.profile

# Source .bashrc if it exists, so aliases and functions are available
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

This is the bridge that makes an SSH session (a login shell) inherit the aliases defined in .bashrc. Without it, the aliases work in the terminal but not over SSH, which is one of the most common configuration complaints .


c. Aliases vs functions, and the non-interactive limitation

An alias is the right tool for a fixed substitution: a shorter name for a long command, a default flag added to a common command, a typo correction. It is the wrong tool for anything that needs arguments, conditionals, loops, or error handling. The Bash manual’s recommendation is explicit: use a function instead .

# Alias: fixed substitution, no arguments
alias ll='ls -alF'

# Function: accepts arguments, can contain logic
mkcd() {
    mkdir -p "$1" && cd "$1"
}

The function mkcd takes a directory name as an argument, creates it, and changes into it. An alias cannot do this because it cannot reference $1—the alias value is a literal string, and the argument is appended at the end, not substituted into the middle .

The non-interactive limitation is the other boundary. A script that needs an alias must either enable expand_aliases and source the file, or use a function or a full path instead:

#!/bin/bash
# Enable alias expansion in this non-interactive script
shopt -s expand_aliases
# Source the file that defines the aliases
source "$HOME/.bashrc"

# Now the alias is available
ll /tmp

The Bash manual and the Baeldung guide both recommend limiting alias use in scripts. The script can break if the alias is removed or if the environment is different, and a function or a full command is more portable .

For system-wide aliases, the file is /etc/profile.d/ with a .sh extension. Files there are sourced by /etc/profile for all users, but they are read by login shells, so the same bridge consideration applies .


Complete Example Session

The following session creates aliases, persists them, verifies the shell type behavior, and demonstrates the function alternative for an argument-taking shortcut.

# ============================================
# PART 1: CREATE AND TEST A TEMPORARY ALIAS
# ============================================
# Define an alias in the current shell
alias ll='ls -alF'

# Verify it exists
alias ll
# Output: alias ll='ls -alF'

# Use it
ll /tmp
# Output: detailed listing of /tmp

# ============================================
# PART 2: PERSIST IN ~/.bashrc
# ============================================
# Append the alias to .bashrc
echo "alias ll='ls -alF'" >> ~/.bashrc

# Apply the change to the current shell
source ~/.bashrc

# ============================================
# PART 3: VERIFY LOGIN SHELL BEHAVIOR
# ============================================
# Start a login shell (simulates SSH)
bash --login

# The alias is available only if .profile sources .bashrc
ll /tmp
# If "command not found", the bridge is missing

# Exit the login shell
exit

# ============================================
# PART 4: ADD THE BRIDGE (IF NEEDED)
# ============================================
# Add the source line to .profile
echo 'if [ -f ~/.bashrc ]; then . ~/.bashrc; fi' >> ~/.profile

# ============================================
# PART 5: FUNCTION FOR ARGUMENT-TAKING SHORTCUT
# ============================================
# Add a function to .bashrc
cat >> ~/.bashrc << 'EOF'
# Create a directory and enter it
mkcd() {
    mkdir -p "$1" && cd "$1"
}
EOF

source ~/.bashrc
mkcd /tmp/testdir
pwd
# Output: /tmp/testdir

The five parts cover the temporary alias, the persistence in .bashrc, the login shell verification, the bridge in .profile, and the function alternative for argument handling. What the session demonstrates is that the alias works immediately but does not survive a new shell unless persisted, and that the login shell does not see the alias unless the bridge is in place.


Quick Reference

Core Commands

CommandPurpose
alias name='command'Create an alias
aliasList all aliases
alias nameShow one alias
unalias nameRemove one alias
unalias -aRemove all aliases

Persistence

FilePurpose
~/.bashrcAliases for interactive shells
~/.bash_profile / ~/.profileLogin shell; must source .bashrc
/etc/profile.d/*.shSystem-wide (login shells)

Shell Type Behavior

Shell TypeReads .bashrc?Aliases Available?
Interactive non-login (terminal)YesYes
Login (SSH, bash --login)Only if sourcedOnly if bridged
Non-interactive (script)NoNo, unless expand_aliases

Alias vs Function

AspectAliasFunction
ArgumentsNoYes
Logic (loops, conditionals)NoYes
ExportableNoYes (export -f)
Recommended for scriptsNoYes

Best Practices

✅ Do This:

# Put aliases in .bashrc
alias ll='ls -alF'

# Source .bashrc from .profile for login shells
if [ -f ~/.bashrc ]; then . ~/.bashrc; fi

# Use a function when arguments are needed
mkcd() { mkdir -p "$1" && cd "$1"; }

❌ Don’t Do This:

# Put aliases in .profile
alias ll='ls -alF'  # not read by interactive non-login shells

# Define and use an alias on the same line
alias ll='ls -alF'; ll  # fails

# Expect sudo to inherit aliases
sudo ll  # "command not found"

Common Pitfalls

PitfallWhy It HappensFix
Alias works in terminal, not SSH.bashrc not sourced by login shellAdd bridge to .profile
Alias fails in scriptNon-interactive shellshopt -s expand_aliases + source
sudo ll failsAlias not expanded in sudoUse sudo ls -alF
Alias not available after editShell not reloadedsource ~/.bashrc
Alias cannot use $1Aliases do not take argumentsUse a function

Real-World Examples

1. Basic alias

alias ll='ls -alF'

2. Safety alias

alias rm='rm -i'

3. Git shortcut

alias gs='git status'

4. Persistent alias

echo "alias ll='ls -alF'" >> ~/.bashrc

5. Reload aliases

source ~/.bashrc

6. Remove alias

unalias ll

7. Bridge for login shells

if [ -f ~/.bashrc ]; then . ~/.bashrc; fi

8. Function for arguments

mkcd() { mkdir -p "$1" && cd "$1"; }

9. Enable aliases in script

shopt -s expand_aliases

10. List aliases

alias

Visual

Alias Expansion

┌──────────────────────────────────────────────┐
│  User types: ll /tmp                         │
│         │                                    │
│         ▼                                    │
│  Shell reads the line                        │
│         │                                    │
│         ▼                                    │
│  Alias match: ll → ls -alF                   │
│         │                                    │
│         ▼                                    │
│  Executes: ls -alF /tmp                      │
└──────────────────────────────────────────────┘

Shell Type and Alias Availability

┌──────────────────────────────────────────────┐
│  TERMINAL (interactive non-login)            │
│  reads ~/.bashrc → alias available           │
│                                              │
│  SSH (login)                                 │
│  reads ~/.profile                            │
│  if .profile sources .bashrc → available     │
│  else → not available                        │
│                                              │
│  SCRIPT (non-interactive)                    │
│  reads neither → not available               │
│  unless expand_aliases + source              │
└──────────────────────────────────────────────┘

Alias vs Function

┌──────────────────────────────────────────────┐
│  ALIAS: ll='ls -alF'                         │
│  ll /tmp → ls -alF /tmp                      │
│  Argument appended, no logic                 │
│                                              │
│  FUNCTION: mkcd() { mkdir -p "$1" && cd "$1"; } │
│  mkcd /tmp → creates and enters /tmp         │
│  Argument referenced as $1, logic allowed    │
└──────────────────────────────────────────────┘

Persistence Chain

┌──────────────────────────────────────────────┐
│  ~/.bashrc                                   │
│  alias ll='ls -alF'                          │
│         │                                    │
│         ▼                                    │
│  ~/.profile (login shell)                    │
│  if [ -f ~/.bashrc ]; then . ~/.bashrc; fi   │
│         │                                    │
│         ▼                                    │
│  SSH login shell sees the alias              │
└──────────────────────────────────────────────┘

Summary

ItemValue
Create aliasalias name='command'
Remove aliasunalias name
List aliasesalias
Persistence file~/.bashrc
Login shell bridgeSource .bashrc from .profile
Non-interactiveshopt -s expand_aliases
ArgumentsUse a function, not an alias
sudoDoes not inherit aliases

Key takeaways:

  • An alias is a text substitution. The shell replaces the alias name with its value before executing the command. It cannot take arguments, contain logic, or reference $1 .
  • Aliases belong in ~/.bashrc. That is the file read by interactive non-login shells. Putting aliases in .profile does not work for terminal sessions .
  • Login shells need a bridge. SSH sessions read .profile or .bash_profile, not .bashrc. The if [ -f ~/.bashrc ]; then . ~/.bashrc; fi line makes the aliases available in both .
  • Non-interactive shells do not expand aliases by default. A script must set shopt -s expand_aliases and source the file, or use a function or full command instead .
  • Functions are preferable for anything with arguments or logic. The Bash manual recommends functions over aliases for almost every purpose .
  • sudo does not inherit aliases. sudo ll fails because the alias was never expanded in the sudo context. Use the expanded command or a function .

Remember: Aliases are a convenience for interactive shells. They make long commands shorter and add default flags, but they are limited by design: no arguments, no logic, no non-interactive expansion. The LFCS exam expects you to know where aliases are defined (~/.bashrc), how they are persisted (the source line in .profile), and when to use a function instead (when arguments or logic are needed). The bridge between .profile and .bashrc is the detail that separates a configuration that works in the terminal from one that works over SSH.


Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!