9

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.

oligofren
  • 679
  • 1
  • 9
  • 24

2 Answers2

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!"
Olorin
  • 3,548
4

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.