DEV Community

Franklin Yu
Franklin Yu

Posted on

How the shell aliases affect shell functions: two pitfalls

If you have this in your .bashrc:

alias foo=bar
foo() {
    echo 1
}
Enter fullscreen mode Exit fullscreen mode

You would expect the alias to “shadow” the function, so when you execute foo you think it is executing bar instead of echo 1. Right?

Wrong! The alias takes immediate effect, so when Bash sees the function definition, it actually regard it as

bar() {
    echo 1
}
Enter fullscreen mode Exit fullscreen mode

which defines a function named bar. So you end up with foo as an alias, and bar as a function. Zsh is a bit better in this case; if Zsh sees the same snippet trying to define a function after alias, the function-definition command will fail (since defining bar as a function is almost never intended anyway). To fix it, define the function with the function keyword instead, whenever POSIX-compliance isn’t needed. This fix works both in Bash and in Zsh.

Another interesting behavior is how Bash and Zsh expand aliases in function bodies. For example:

alias ls='ls --color'
function ls_repos() {
    ls ~/repos  # expands to "ls --color ~/repos"
}
Enter fullscreen mode Exit fullscreen mode

The order between the alias and the function is important, because aliases are expanded when the function is defined, not when it is called. The ls in the function body is expanded only if the alias exists before the function is defined. When you query the function definition with type -f you actually see the one after the expansion.

This behavior is actually well-documented. In Bash documentation:

Aliases are expanded when a function definition is read, not when the function is executed, because a function definition is itself a command.

Zsh documentation:

Note that aliases are expanded when the function definition is parsed, not when the function is executed.

On the plus side, one can make use of this behavior to avoid some annoyance. For example, if one of your alias in your .bashrc breaks some external script (such as nvm.sh), you can simply move the alias around in your .bashrc, defining them after sourcing nvm.

Top comments (0)