In Bash, when to alias, when to script, and when to write a function?
The other answers provide some soft general guidelines based on personal taste, but ignore many pertinent facts that one should consider when deciding between scripts, functions, or aliases.
Aliases and Functions ¹
- The entire contents of aliases and functions are stored in the shell's memory.
- A natural consequence of this is aliases and functions can only be used by the current shell, and not by any other programs you may invoke from the shell like text editors, scripts, or even child instances of the same shell.
- Aliases and functions are executed by the current shell, i.e. they run within and affect the shell's current environment.² No separate process is necessary to run an alias or function.
Scripts
- Shells do not keep scripts in memory. Instead, scripts are read from the files where they are stored every time they are needed. If the script is found via a
$PATH
search, many shells store a hash of its path name in memory to save time on future$PATH
look-ups, but that is the extent of a script's memory footprint when not in use. Scripts can be invoked in more ways than functions and aliases can. They can be passed as an argument to an interpreter, like
sh script
, or invoked directly as an executable, in which case the interpreter in the shebang line (e.g.#!/bin/sh
) is invoked to run it. In both cases, the script is run by a separate interpreter process with its own environment separate from that of your shell, whose environment the script cannot affect in any way. Indeed, the interpreter shell does not even have to match the invoking shell. Because scripts invoked this way appear to behave like any ordinary executable, they can be used by any program.Finally, a script can be read and run by the current shell with
.
, or in some shells,source
. In this case, the script behaves much like a function that is read on-demand instead of being constantly kept in memory.
Application
Given the above, we can come up with some general guidelines for whether to make something a script or function / alias.
Do other programs besides your shell need to be able to use it? If so, it has to be a script.
Do you only want it to be available from an interactive shell? It's common to want to change the default behavior of many commands when run interactively without affecting external commands / scripts. For this case, use an alias / function set in the shell's "interactive-mode-only" rc file (for
bash
this is.bashrc
).Does it need to change the shell's environment? Both a function / alias or a sourced script are possible choices.
Is it something you use frequently? It's probably more efficient to keep it in memory, so make it a function / alias if possible.
Conversely, is it something you use only rarely? In that case, there's no sense having it hog memory when you don't need it, so make it a script.
¹ While functions and aliases have some important differences, they are grouped together because functions can do everything aliases can. Aliases can not have local variables nor can they process arguments, and they are inconvenient for anything longer than one line.
² Every running process in a Unix system has an environment consisting of a bunch of variable=value
pairs which often contain global configuration settings, like LANG
for the default locale and PATH
for specifying executable search path.
An alias should effectively not (in general) do more than change the default options of a command. It is nothing more than simple text replacement on the command name. It can't do anything with arguments but pass them to the command it actually runs. So if you simply need to add an argument at the front of a single command, an alias will work. Common examples are
# Make ls output in color by default.
alias ls="ls --color=auto"
# make mv ask before overwriting a file by default
alias mv="mv -i"
A function should be used when you need to do something more complex than an alias but that wouldn't be of use on its own. For example, take this answer on a question I asked about changing grep
's default behavior depending on whether it's in a pipeline:
grep() {
if [[ -t 1 ]]; then
command grep -n "$@"
else
command grep "$@"
fi
}
It's a perfect example of a function because it is too complex for an alias (requiring different defaults based on a condition), but it's not something you'll need in a non-interactive script.
If you get too many functions or functions too big, put them into separate files in a hidden directory, and source them in your ~/.bashrc
:
if [ -d ~/.bash_functions ]; then
for file in ~/.bash_functions/*; do
. "$file"
done
fi
A script should stand on its own. It should have value as something that can be re-used, or used for more than one purpose.
I think it's up to each person's taste. For me the logic goes like this:
- First I try to make an alias, because it's the simplest.
- If the thing is too complicated to fit in one line, I try to make it a function.
- When the function starts to grow beyond a dozen of lines I put it in a script.
There is really nothing to restrict you from doing something that works.