0
~$ bash --version
GNU bash, version 5.1.12(1)-release (x86_64-pc-linux-gnu)
~$ alias bab=python
~$ $(echo bab)
bash: bab: command not found

I'd expect bab to be turned to "python", but it seems it's not.

~$ $(echo alias)
alias bab='python'
alias ls='ls --color=auto'
~$ bab
Python 3.10.1 (main, Dec 11 2021, 17:22:55) [GCC 11.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

The alias is recognized though, and works outside the interpolation. Why won't it work inside the interpolation?

eval works:

~$ eval $(bab)
Python 3.10.1 (main, Dec 11 2021, 17:22:55) [GCC 11.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

I still wonder why

Kusalananda
  • 333,661
Nitz
  • 143
  • 2
    What do you mean by "works"? With eval $(bab) you would evaluate the output of bab. Yes, it runs python, but that's before it gets to eval. What is it that you are trying to achieve? – Kusalananda Jan 20 '22 at 16:32
  • 1
    eval $(bab) isn't doing what you think it's doing - you're seeing the bab alias running python. When that's completed the results will get passed to eval. You can see this by running a command in the python session such as print("date\n") – Chris Davies Jan 20 '22 at 16:33
  • I reopened. This Q is not a duplicate of this. – glenn jackman Jan 20 '22 at 16:49
  • though $(echo xyz) in particular is pretty much useless, same as echo $(zyx). But I assume you actually have some other expansion there. – ilkkachu Jan 20 '22 at 17:04
  • If you do eval $(bab), or equally, eval $(python), and try e.g. print("hello") in the interpreter, you'll see the output doesn't appear on the screen. Instead, when you exit the interpreter, Bash will complain about not finding the command hello... When starting the python interpreter in a command substitution, it's output is captured by the shell. It just prints the command line to the terminal, bypass the command substitution. You probably don't want that. Something like var=$(python script.py) would make more sense, of course. – ilkkachu Jan 20 '22 at 17:08
  • Also note that using $(anything) would not just run anything, it would expand the output of that command, split the output on the characters in $IFS, and apply filename globbing on the resulting strings. Then it would treat the first word as a command. It's unclear why you are attempting to use this syntax. – Kusalananda Jan 20 '22 at 17:35
  • @glennjackman how do I put in a vote for a suggested dup instead of wielding a hammer? – Chris Davies Jan 20 '22 at 17:55
  • The tag gold badge comes with surprising powers sometimes. Perhaps just a comment? – glenn jackman Jan 20 '22 at 23:59
  • It's because $() starts a subshell without the alias of the parent shell. – Alexander Jan 28 '22 at 18:37

2 Answers2

3

Aliases get expanded before command substitution, documented in 3.1.1 Shell Operation. The "bab" that gets executed after $(echo bab) will not be handled as an alias.

Try using a function instead:

unalias bab
bab() { python "$@"; }
$(echo bab)       # launches a python shell
glenn jackman
  • 85,964
  • Why would you ever want to use $(echo bab) in place of just bab though? – Kusalananda Jan 20 '22 at 17:36
  • 1
    Normally you wouldn't of course. I approached this question more as a "why does bash behave like this in this corner case". – glenn jackman Jan 21 '22 at 00:01
  • My real usecase is that inside $() I had a command that prints what I want to run (specifically, jq <package.json .scripts.test -r). Happy to explain more in case someone is interested. – Nitz Jan 23 '22 at 09:10
1

From man bash

Aliases allow a string to be substituted for a word when it is used as the first word of a simple command.

AlexD
  • 1,173