7

In my dotfiles I have some functions that rely on aliases or functions to exist for them to work. For some reason, I can get them to reference other functions I have created, but not aliases for commands. How do I fix this?

Example:

function open-dotfiles-commit(){ 
    xopen https://github.com/fatso83/dotfiles/blob/$1; 
}

If I have an alias xopen (alias xopen=xdg-open), the open-dotfiles-commit command will fail with xopen: cannot find command. On the other hand, if I replace the alias definition with a function called xopen (function xopen(){ xdg-open; };) it works!

I have even tried setting shopt -s expand_aliases in the same file as where I define the aliases - unsuccessfully. The alias and functions file is sourced by my .bashrc.

3
  • Can you post ~/.bashrc and the alias file?
    – j-money
    Mar 5, 2019 at 10:46
  • @j-money I linked to the whole setup in my github dotfiles repo. It is way to complex/involved to post here, as it consists of 3-4 intertwined files. I did get a correct answer, though.
    – oligofren
    Mar 5, 2019 at 12:03
  • Simply use eval in front of your command.
    – SOFe
    Jan 23, 2021 at 14:09

2 Answers 2

10

From the bash manual:

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

I'd bet that your aliases are defined after these functions are defined. Try defining the functions later.

For reference, I tested foo () { ll "$1"; }, using the ll alias from the default .bashrc, and it worked fine.

Runnable example:

def-before() { do-foo; };    
alias do-foo="echo foo u!"    
def-after() { do-foo; };

def-before 
# prints "do-foo: Could not find command"

def-after
# prints "foo u!"
1
  • 1
    That was exactly it. I edited your post and added the executable example I verified your answer with.
    – oligofren
    Mar 5, 2019 at 12:02
3

Olorin's answer did not solve my calling-aliases-in-a-shell-function problem. I recommend avoiding bash aliases, because (quote from the bash manual below): For almost every purpose, shell functions are preferred over aliases.

To illustrate by converting do-foo in Olorin's answer from an alias to a shell function (while also making sure to add semicolons for one-line shell functions), defining said do-foo shell function (that was originally an alias) before using it in another shell function, and for fun: redefining do-foo() and then recalling def-after():

$ do-foo()    { echo 'hello foo'; }
$ def-after() { do-foo; }
$ def-after
hello foo
$ do-foo()    { echo 'this is fooey'; }
$ def-after
this is fooey
$
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.5 LTS
Release:    20.04
Codename:   focal
$

More details

I had the same error as the OP in one of my bash scripts and Olorin's answer did not solve it. This is apparently because aliases (by default) do not exand in non-interactive environments, like most all my bash scripts (including the one I mention above), as highlighted below. Once I converted all my aliases to shell functions everything worked as expected.

I now avoid bash aliaes and try to instead exclusively employ shell functions.

Excerpts from the bash manual section on aliases:

  1. Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see The Shopt Builtin).

  2. For almost every purpose, shell functions are preferred over aliases.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .