Wizard
Wizard

Reputation: 22113

echo $(!ls) does not output the variable name

There are two kinds of parameter expansions that return variable names specified on bash documentation.

${!prefix*}
This expansion returns the names of existing variables with names beginning with prefix.

${!name[@]}
If name is an array variable, expands to the list of array indices (keys) assigned in name.

There are cases out of the scope:

    $ foo=1
    $ echo $((${!foo}))
    0

    $ echo $(!ls)
    echo $(ls -l)
    total 272 -rw-r--r-- 1 me staff 0 Apr 8 16:37 2 
    ...

What's the mechanism behind it?

Upvotes: 1

Views: 183

Answers (1)

chepner
chepner

Reputation: 531798

${!foo} and ${!foo*} are two very different expressions. ${!foo} expands to the value of the variable whose name is stored in foo:

$ foo=bar
$ bar=5
$ echo ${!foo}  # => echo $bar
5

${!foo*} expands to the names of variables beginning with foo

$ foo1=1 foo2=2
$ echo ${!foo*}
foo1 foo2

$(!ls) is not a parameter expansion at all; it is a history subsitution inside a command substitution. !ls first expands to the most recent command starting with ls, which is ls -l in your example. That string is then executed by the command substitution, and the output is captured to be used as the argument to the echo command.

$ echo $(!ls) => echo $(ls -l) => echo total 272 -rw-r--r-- 1 me staff 0 Apr 8 16:37 2
total 272 -rw-r--r-- 1 me staff 0 Apr 8 16:37 2

Upvotes: 4

Related Questions