alias Command in Linux: Complete Guide to Creating Shell Aliases and Parameters

alias command in Linux and it perimeters

I type git status probably two hundred times a day, and at some point in my early sysadmin years I got tired of it and just made it gs. That one habit — building a personal shorthand for the commands I run constantly — is the entire reason the alias command exists, and it’s still one of the first things I set up on any new machine I touch. In this guide I want to walk through everything I know about alias: the syntax, the quirks that trip people up (including one that got me just last week while testing scripts), how it actually works under the hood, and how to use it properly in real sysadmin work instead of just typing ll in your personal terminal.

What alias Actually Is

alias is a shell builtin, not a standalone binary. You won’t find it in /usr/bin or /bin — it lives inside the shell itself (bash, zsh, dash, etc.), which is why its behavior differs slightly between shells and why you can’t call it from a compiled program or from system() in C without going through a shell.

At its core, an alias is a simple text-substitution rule. When the shell reads a command line and the first word matches a defined alias, it swaps that word for the alias’s replacement text before doing anything else — before parsing arguments, before checking $PATH, before anything. That’s the whole trick, and it explains almost every quirk you’ll run into.

I confirmed this directly:

$ type alias
alias is a shell builtin

Basic Syntax

alias [-p] [name[=value] ...]
  • Called with no arguments, alias lists every alias currently defined.
  • Called with -p, it lists them in a form that’s guaranteed to be re-usable as input (useful in scripts that dump your environment).
  • Called with name=value, it defines (or redefines) an alias.
  • Called with just name (no =value), it prints that one alias’s definition.

Here’s a plain definition and lookup I ran myself:

$ alias ll='ls -la'
$ alias
ll='ls -la'
$ alias ll
ll='ls -la'

Notice the quoting. If your replacement text contains spaces (and it almost always does), you need to quote it. I always use single quotes unless I specifically want variable expansion to happen at definition time rather than at call time.

Removing an Alias

The counterpart command is unalias:

unalias name        # remove one alias
unalias -a           # remove all aliases in the current shell

I tested this directly and it behaves exactly as documented:

$ alias ll='ls -la'
$ unalias ll
$ alias ll
bash: alias: ll: not found

That “not found” message is bash telling you the name isn’t a defined alias — it’s not an error in your command, just confirmation the removal worked.

The Gotcha: Aliases Don’t Expand in Non-Interactive Shells by Default

This one caught me off guard while I was testing examples for this very article. I wrote a small script, ran it, and my alias silently failed:

$ bash -c 'alias greet="echo hello"; greet world'
bash: line 1: greet: command not found

The reason is that bash only expands aliases in interactive shells by default. A script run with bash -c or bash script.sh is non-interactive, so alias expansion is off unless you explicitly turn it on with shopt:

$ bash -c 'shopt -s expand_aliases; alias greet="echo hello"; greet world'
hello world

This is exactly why the standard advice is don’t rely on aliases inside shell scripts — use functions instead. Aliases are a login-shell/interactive convenience, not a scripting tool. I’ll come back to this point in the best-practices section because it matters for anyone writing production automation.

alias Does Not Take Positional Parameters

This is the single most common misunderstanding I see from people coming from other languages. An alias is text substitution, not a function call — it has no concept of $1, $2, or argument placement inside the replacement text. Whatever you type after the alias name just gets appended to the end of the expanded text.

$ alias greet='echo hello'
$ greet world
hello world

That works because world gets tacked onto the end of echo hello, producing echo hello world. But if you wanted to insert an argument in the middle of a command, aliases can’t do it:

$ alias cpv='cp -v'
$ cpv file1.txt /tmp/
# expands to: cp -v file1.txt /tmp/    -> works fine, args go at the end

But something like “always compress before copying” with an argument placed mid-command is impossible with an alias. For that, you need a shell function:

backup_and_copy() {
    tar czf "$1.tar.gz" "$1" && cp "$1.tar.gz" "$2"
}

I keep this rule in my head permanently: if the command needs logic, conditionals, or an argument that isn’t simply appended at the end, it’s a function, not an alias.

Nested Aliases

Aliases can reference other aliases, and bash resolves them at expansion time:

$ shopt -s expand_aliases
$ alias ll='ls -la'
$ alias la='ll -A'
$ type la
la is aliased to `ll -A'

This works, but I try not to build deep chains of aliases referencing aliases — it gets confusing to debug two weeks later when you forget which alias points to which.

Aliasing sudo-Prefixed Commands

A common pattern I use on servers I manage directly:

alias update='sudo apt update && sudo apt upgrade -y'
alias ports='sudo ss -tulnp'

One subtlety worth knowing: if you want a command following a sudo alias to also have alias expansion applied (say, you have another alias for the command sudo is running), you need a trailing space in the sudo alias:

alias sudo='sudo '

That trailing space is not a typo — it tells bash “keep checking for more alias expansion after this word,” which is needed because by default alias expansion only looks at the first word of a command.

Persisting Aliases Across Sessions

Everything above only lives in your current shell session. Close the terminal and it’s gone. To make aliases permanent, put them in your shell’s startup file:

  • bash (interactive login shells): ~/.bash_profile or ~/.profile
  • bash (interactive non-login shells, most terminal emulators): ~/.bashrc
  • zsh: ~/.zshrc

I keep mine in a separate file and source it, which makes it easier to manage under version control:

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

Then all my actual alias definitions live in ~/.bash_aliases, which I sync across machines with a dotfiles repo.

System-Wide Aliases

For aliases you want available to every user on a machine, drop a file into /etc/profile.d/ (for login shells) or edit /etc/bash.bashrc (for interactive non-login shells). I use this on shared servers to enforce safety habits team-wide:

# /etc/profile.d/safety-aliases.sh
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

Practical Aliases I Actually Use

These are pulled straight from my own .bash_aliases:

# Listing
alias ll='ls -la'
alias la='ls -A'
alias l='ls -CF'

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

# Navigation
alias ..='cd ..'
alias ...='cd ../..'

# Git shortcuts
alias gs='git status'
alias gd='git diff'
alias gl='git log --oneline --graph --decorate'

# System admin
alias meminfo='free -h'
alias diskinfo='df -h'
alias ports='sudo ss -tulnp'

# Networking
alias myip='curl -s ifconfig.me'

# Package management (Debian/Ubuntu)
alias update='sudo apt update && sudo apt upgrade -y'

Overriding a Real Command with an Alias — And How to Bypass It

Once you alias rm='rm -i', typing rm file.txt really runs rm -i file.txt, prompting before every delete. That’s great for safety, but sometimes you genuinely want the raw command. Three ways to bypass an active alias:

\rm file.txt          # backslash disables alias expansion for that word
command rm file.txt   # 'command' also skips aliases and functions
env rm file.txt        # runs the actual binary via env, also bypasses aliases

I use \rm constantly in scripts that need the unmodified behavior of the real binary, and it’s a habit worth building.

How alias Interacts with $PATH and Functions

There’s a resolution order the shell follows when it sees a command word:

  1. Aliases (if expansion is enabled)
  2. Shell keywords (if, for, etc.)
  3. Shell functions
  4. Shell builtins
  5. Executables found by searching $PATH

Because aliases are resolved first, an alias named the same as a real command (like rm, ls, grep) will always win unless you explicitly bypass it. This is powerful but also a trap: if you forget you’ve aliased grep='grep --color=auto' and then wonder why piping grep output into another program behaves oddly (color codes leaking into a file), the alias is almost always the cause.

Troubleshooting Aliases

A few things I check when an alias “isn’t working”:

  • Am I in a script? Alias expansion is off by default in non-interactive shells (see above). Use shopt -s expand_aliases or, better, rewrite as a function.
  • Did I actually reload my shell config? Editing ~/.bashrc doesn’t affect already-open sessions. Run source ~/.bashrc or open a new terminal.
  • Is there a typo in the source file? A broken alias definition can silently abort the rest of the file from loading in some shells. I check with bash -n ~/.bashrc to syntax-check without executing.
  • Is another alias or function shadowing it? type name tells you exactly what the shell will run for that word — alias, function, builtin, or file path.
$ type ls
ls is aliased to `ls --color=auto'

alias vs. Shell Functions vs. Scripts

I get asked which one to use, so here’s how I decide:

Featurealiasshell functionstandalone script
Argument placementEnd onlyAnywhere ($1, $2, …)Anywhere
Conditionals/loopsNoYesYes
Works in scripts by defaultNoYesYes
Persists across shell restartOnly if in rc fileOnly if in rc fileAlways (it’s a file)
Callable from other programs/cronNoNo (unless exported)Yes
Best forQuick shorthand, flag defaultsSmall reusable logicAnything reused across systems or users

My rule of thumb: aliases for shorthand you type interactively, functions for logic you want in your interactive shell, and scripts for anything that needs to run outside your terminal — cron jobs, other users, CI pipelines.

Security Considerations

Aliases are a legitimate (if uncommon) vector for confusion or mischief on shared systems. Because alias resolution happens before $PATH lookup, a malicious or careless alias can silently redirect a trusted command name to something else entirely. A few practices I follow:

  • Never source an untrusted .bashrc or dotfiles repo without reading it first.
  • On systems where multiple people have shell access, be cautious about what you put in shared files under /etc/profile.d/.
  • If you’re auditing a compromised or suspicious system, always check alias output (and type for common commands like ls, sudo, ssh) as part of your review — it’s a cheap check that occasionally reveals something odd.
  • Aliases are never a security boundary. They’re a convenience layer for interactive use, easily bypassed with \command or command.

Compatibility Across Shells

alias syntax as described here (alias name=value) is the bash/zsh/ksh style and is what you’ll use in virtually every interactive Linux terminal. Two things worth knowing:

  • dash (Ubuntu/Debian’s default /bin/sh) supports alias as a builtin too, but scripts run with #!/bin/sh on Debian-based systems point at dash, where alias expansion in non-interactive mode is also disabled — reinforcing why aliases don’t belong in portable scripts.
  • csh/tcsh use a different syntax entirely (alias name 'value' with no =), which is one more reason POSIX-style scripting avoids aliases altogether.

Across Ubuntu, Debian, Fedora, RHEL, Arch, and basically every mainstream distro, bash’s alias builtin behaves identically since it’s part of bash itself, not the distro’s packaging.

Summary

alias is a shell builtin that performs simple text substitution on the first word of a command line before any other parsing happens. It’s fantastic for interactive shorthand — shortening long commands, adding safety flags, or setting personal defaults — but it has real limits: no argument placement beyond the end of the string, no conditionals, and disabled expansion in non-interactive shells by default. For anything with logic or that needs to run in scripts, cron, or by other users, reach for a shell function or a proper script instead. Keep your aliases in a dedicated dotfile, version-control them, and remember \command or command when you need to bypass one temporarily.

References

  • GNU Bash Reference Manual, “Aliases” section — https://www.gnu.org/software/bash/manual/bash.html#Aliases
  • man bash (Builtin Commands section covers alias/unalias)
  • Debian Policy Manual on shell scripts and /bin/sh — https://www.debian.org/doc/debian-policy/
Total
0
Shares

Leave a Reply

Previous Post
whatis command in Linux and it perimeters

whatis Command in Linux: Complete Guide to One-Line Command Descriptions and Parameters

Next Post
type command in Linux and it perimeters

type Command in Linux: Complete Guide to Command Type Identification and Parameters

Related Posts