Aliases in the shell: increase efficiency and avoid errors
An alias replaces the first word of a command line before the shell runs it. This article shows how to create aliases in Bash and Zsh, how to store them permanently in ~/.bashrc or ~/.zshrc, how to remove them again, why they do nothing inside scripts without expand_aliases, why they cannot take arguments, and when a shell function is the better choice.
Every shell session has a handful of commands you type more than all the others. git status. ls -l. cd ... An alias turns each of them into two or three keystrokes, and it takes the typo with it.
This article covers how to create an alias, how to make it survive the next login, and how to get rid of it again. It also covers the two places where aliases quietly do nothing: inside scripts, and whenever an argument has to go somewhere other than at the end. The examples were reproduced with Bash 5.2.21 on Ubuntu 24.04; the current release is Bash 5.3, dated 30 July 2025. Zsh behaves the same except where noted.
What is an alias in the shell?
An alias is a short name that stands in for a command. The shell substitutes it while it reads the line, and only then runs whatever the substitution produced. The Bash manual puts it in one sentence: “Aliases are expanded when a command is read, not when it is executed”. Almost everything below follows from it.
Only the first word of a command line is replaced. ll at the start of a line expands, echo ll does not. Whatever you append stays untouched and ends up after the substitution.
That rule has a well known consequence. sudo ll does nothing useful, because ll is not the first word there. The manual also supplies the fix: “If the last character of the alias value is a blank, then the shell checks the next command word following the alias for alias expansion.” So alias sudo='sudo ', with the trailing space, brings sudo ll back. Setting up sudo itself is covered in How to use Sudo on Debian.
Definition and purpose
The point is a narrow one: fewer keystrokes, fewer typos. ll instead of ls -la, gs instead of git status. Arguments come along for the ride, so ll /etc becomes ls -la /etc. An alias is closer to a text substitution than to a program of its own.
Advantages of using aliases
Three things improve. You type less. You mistype less often, because the long form was written once and then stays written. And the line reads better, since gs states its purpose faster than a run of options.
None of that travels with you. An alias only you know makes your command line unreadable to everyone else, and on somebody else’s server it is not there at all. Documentation and scripts get the long form.
Examples of useful aliases
ll for ls -l and gs for git status are the usual suspects. The valuable ones are the aliases nobody else would think of. If you keep ending up in the same project directory, alias cdproj='cd ~/projects' earns its line. If you check regularly which services are listening, shorten the command from How to Show Used Ports in Linux. What makes an alias worth having is not how clever it is, but how often you reach for it.
Creating aliases in the Linux and Mac terminal
An alias is a single line. It takes effect at once, but only in the shell you typed it into. To survive the day it has to go into a startup file.
Syntax for creating an alias
The syntax is fixed by POSIX.1-2024, Issue 8 of the Base Specifications, and is the same in Bash and Zsh:
alias name='Command'
name is the abbreviation, Command the text put in its place. No spaces around the equals sign. For example:
alias ll='ls -l'
The quotes are not a formality, and they are not always required either. You need them as soon as the command contains a space or a shell metacharacter, because otherwise everything after the space is read as a further argument to alias. That is why alias ll=ls works without them and alias ll=ls -l does not.
Single quotes are the safer default. Inside double quotes the shell evaluates $ and backticks when the alias is defined rather than when it is used, so alias pwd2="echo $PWD" freezes whichever directory you happened to be in.
Three habits are worth picking up straight away:
aliaswith no argument lists everything currently set.type llsays whetherllis an alias, a function or a real program. It is the fastest way to catch a name collision before it catches you at an awkward moment.Alias names cannot contain spaces.
Temporary and permanent aliases
An alias typed into a running shell does not outlive the window. Close the terminal and it is gone. It becomes permanent only in a startup file, and which file that is depends on the shell.
Bash reads ~/.bashrc for interactive shells that are not login shells. If your terminal starts a login shell instead, the file actually read is ~/.bash_profile, and the common templates source ~/.bashrc from there. Zsh reads ~/.zshrc. On a Mac, Zsh has been the default for newly created accounts since macOS 10.15 (Apple Support), which makes ~/.zshrc the right address there. Put the line in the wrong file and you will spend a while hunting a bug that does not exist.
After editing, either open a new terminal or read the file in by hand:
source ~/.bashrc
From then on the alias is available in every new session. One drawback remains: the startup file grows. Once you keep more than a handful of aliases, put them in a file of their own and source it from the startup file. Ubuntu anticipates this already; /etc/skel/.bashrc on Ubuntu 24.04 contains:
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
Where aliases do not apply
Two limits come up again and again. Both are written out in the Bash manual, and both follow from the sentence at the top.
Aliases are not expanded in scripts. “Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt”. A script calling ll therefore dies with command not found, even though the alias sits in your .bashrc and works perfectly in the terminal. To switch expansion on:
shopt -s expand_aliases
source ~/.bash_aliases
Order matters here. Because aliases are expanded as a line is read, the alias has to be known before the line that uses it is read. Defining an alias and calling it on the same line fails every time.
An alias cannot take arguments. The manual leaves no room: “There is no mechanism for using arguments in the replacement text, as in csh. If arguments are needed, use a shell function instead.” Whatever you append lands at the end, and nothing can go in the middle. The moment a value has to sit in a fixed position, you need a function.
Managing and adjusting aliases
Aliases age. Projects change, tools get replaced, and sooner or later your .zshrc holds a shortcut for a command this machine no longer has. Editing and deleting are both quick.
Edit existing aliases
You edit an alias by defining it again. The old definition is overwritten without comment and without a warning. This turns ll from ls -l into ls -la:
alias ll='ls -la'
The new version applies to the running session immediately. It becomes permanent only when you change the line in the startup file as well. Forget that and the next terminal hands you the old version back. A one-line comment above each alias in the startup file costs little and answers the later question of why the alias exists at all.
Delete aliases
A single alias goes away with unalias ll, all of them at once with unalias -a. Either way the effect is limited to the running session.
If the alias also sits in ~/.bashrc or ~/.zshrc, it returns on the next start. The line has to be removed there too. That is not a bug, it is exactly the difference between temporary and permanent.
Best practices for using aliases
An alias you cannot place six months later has missed its purpose. Three habits prevent that.
Useful naming conventions
A good alias name is short and still recognisable. gs for git status is both, x7 is only short. A shared first letter per tool works well: gs, gc and gp for Git, ds and dc for Docker. It saves typing and makes the list searchable, since alias | grep "^alias g" then shows every shortcut starting with g.
One warning belongs here. An alias may carry the same name as an existing program, and it then hides it. Sometimes that is deliberate, sometimes an accident. type name before you create the alias says whether the name is already taken.
Documenting aliases
Aliases are configuration, and configuration without comments is somebody else’s code within a year. One sentence per line is enough. If you use your aliases on more than one machine, keep the file in a repository; then it is also on record when each shortcut arrived and why. Alongside that, alias with no argument remains the quickest view of what is actually set right now.
Functions instead of aliases
As soon as an argument has to land in a particular position, the alias is finished. A function handles it, and it lives in the same file:
mkcd() {
mkdir -p "$1" && cd "$1"
}
Functions are loaded the same way aliases are and additionally understand parameters and return values. Unlike aliases they also work in scripts, with no need to set expand_aliases. The rule of thumb: one word replaced is an alias. The moment logic is involved, it is a function.
Common errors when using aliases
Three mistakes keep coming back. You notice the first two early. The third sometimes surfaces only on somebody else’s machine, which is what makes it unpleasant.
Wrong syntax
The name=value form is strict. No spaces around the equals sign, and quotes as soon as the value contains one:
alias name='Command'
This line, by contrast, does not do what it looks like:
alias ll=ls -l
It does not fail quietly. Bash reports alias: -l: not found, because it reads -l as a second name to look up. At the same time it does create ll, but only for ls without the option. That is what makes the case awkward: there is an error message, and an alias exists afterwards anyway, just the wrong one.
We reproduced this for the article. alias ll then prints alias ll='ls', with no -l. Checking that after every new alias saves the later search.
Overuse of aliases
A long alias list is never used in full. The unused remainder sits in the startup file and confuses you the next time you read through it. Create an alias when the long command has annoyed you for the second or third time, not before.
Cleaning up is part of the job. Workflows change, and an alias for a tool you no longer use is ballast. If the file lives in a repository, the next read-through shows quickly which lines have sat there untouched and unused for years.
When an alias hides a real command
An alias is allowed to share a name with an existing program. alias rm='rm -i' is the popular example: afterwards rm asks before every deletion. That is comfortable until you get used to it. On a server without the alias rm does not ask, and the habit works against you.
For a one-off there are two ways around it that leave the alias alone. A leading backslash bypasses it, so \rm file calls the real rm. command rm file does the same. And type rm tells you in advance which one you are about to get.
Conclusion
An alias is a line in a text file, and that is all it is. The shell replaces the first word as it reads, and leaves the rest alone. Everything else follows from that: no arguments in the middle, no effect in scripts without expand_aliases, no surprise from appended options.
If you are starting out, pick the two or three commands that annoy you most, write the shortcuts into ~/.bashrc or ~/.zshrc, and look again after a few weeks at which ones you actually use. Whatever survives, stays. The rest goes.
Further reading: the Aliases page of the Bash manual and the POSIX specification for alias as primary sources, plus Ubuntuusers: alias (German), IBM: Creating a Command Alias, Pro-Linux: Der Shell-Befehl alias from 2001 (German), Computerworld: How to Use Aliases in Linux Shell Commands from 2012 and IONOS: Linux Alias Befehl (German).