Bash – Fix Bash Aliases Not Expanding with Shopt Expand_Aliases

aliasbash

I want to run an alias inside a bash -c construct.

The bash manual says:

Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt

In this example, why is the alias hi not found when setting expand_aliases explicitly?

% bash -O expand_aliases -c "alias hi='echo hello'; alias; shopt expand_aliases; hi"
alias hi='echo hello'
expand_aliases  on
bash: hi: command not found

I'm running GNU bash, version 5.0.0(1)-release (x86_64-pc-linux-gnu).

Context: I want to be able to run an alias at idle priority, eg a script containing:

#!/bin/bash
exec chrt -i 0 nice -n 19 ionice -c 3 bash -c ". ~/.config/bash/aliases; shopt -s expand_aliases; $(shell-quote "$@")"

I want to avoid using bash -i as I don't want my .bashrc to be read.

Best Answer

It doesn't seem work if you set the alias on the same line as it's used. Probably something to do with how aliases are expanded really early in the command line processing, before the actual parsing stage. On an interactive shell:

$ alias foo
bash: alias: foo: not found
$ alias foo='echo foo'; foo         # 2 
bash: foo: command not found
$ alias foo='echo bar'; foo         # 3
foo
$ foo
bar

Note how the alias used is one line late: on the second command it doesn't find the alias just set, and on the third command it uses the one that was previously set.

So, it works if we put a newline within the -c string:

$ bash -c $'shopt -s expand_aliases; alias foo="echo foo";\n foo'
foo

(You could also use bash -O expand_aliases -c ... instead of using shopt within the script, not that it helps with the newline.)

Alternatively, you could use a shell function instead of an alias, they're much better in other ways, too:

$ bash -c 'foo() { echo foo; }; foo'
foo
Related Question