I see it in someone's shell script file.
#!/bin/bash
var=...
echo "${!var}"
What does "!" mean here?
If the first character of parameter is an exclamation point (!), a
level of variable indirection is introduced. Bash uses the value of
the variable formed from the rest of parameter as the name of the
variable; this variable is then expanded and that value is used in the
rest of the substitution, rather than the value of parameter itself.
This is known as indirect expansion.
There are exceptions to this which are explained here
Example:
$ x=y
$ y=1
$ echo "${x}"
y
$ echo "${!x}"
1
Related
Suppose that parameter=value is an internal variable in bash.
When I try ${#parameter} in bash it returns a 5. But when I try, for instance, ${##parameter} or ${###parameter} it always give back 0 in return.
Why it does not say that it is a substitution error as in other cases?
Short version
You could express ${##parameter} as:
x=$#
${x#parameter}
and ${###parameter} as:
x=$#
${x##parameter}
You are performing a prefix removal on $# (number of arguments passed to a script / function).
Longer version
If parameter has any special meaning, it would be likely specific to your environment.
$ echo \""${parameter}"\"
""
or even:
$ set -u
$ echo \""${parameter}"\"
bash: parameter: unbound variable
Now with that out of the way, quick look into docs:
${#parameter}
The length in characters of the expanded value of parameter is substituted.
So with variable parameter not being set:
$ echo ${#parameter}
0
or with set -u:
$ echo ${#parameter}
bash: parameter: unbound variable
Additional # changed meaning to Remove matching prefix pattern. using: ${parameter#word} or ${parameter##word} syntax on ${#}, i.e. number of argument passed to a script/function. Good way to see and understand that behavior would be:
$ f() { echo -n "$# " ; echo ${##parameter}; }
$ f
0 0
$ f a b c
3 3
As you see in first call ${#} was 0 and (and attempting to strip prefix "parameter" does nothing to it really) and the second call value of ${#} is 3.
Prefix removal, the different between # and ## is, when matching patterns whether shorted or longest match is stripped.
Because ## is a special operator that removes a prefix. See for instance here: What is the meaning of the ${0##...} syntax with variable, braces and hash character in bash?
This question already has answers here:
What is indirect expansion? What does ${!var*} mean?
(6 answers)
Closed 6 years ago.
I have a code block with below condition, not sure what exactly it does.
$var = "${args}_Some_Text"
if [ "${!var}" == '' ];then
echo "$var is not defined !!!"
fi
This is called variable indirect expansion.
$ hello="this is some text" # we set $hello
$ var="hello" # $var is "hello"
$ echo "${!var}" # we print the variable linked by $var's content
this is some text
As you see, it is a way to define "variable variables". That is, to use variables whose content is the name of another variable.
From Bash Reference Manual → 3.5.3 Shell Parameter Expansion:
If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of variable indirection. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. If parameter is a nameref, this expands to the name of the variable referenced by parameter instead of performing the complete indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[#]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.
This question already has answers here:
Create variable from string/nameonly parameter to extract data in bash?
(3 answers)
Closed 8 years ago.
I want to use the output of a echo command as variable name. Like,
var1="test"
var2="script"
echo ${$1}
If $1 is var1 echo should print test.
${$1} throws error "bad substitution"
What you want is called variable expansion (or indirect expansion). You have to use the syntax ${!var}:
~$ cat s.sh
var1="test"
var2="script"
echo ${!1}
~$ ./s.sh var1
test
~$ ./s.sh var2
script
From man bash:
${parameter}
The value of parameter is substituted. The braces are required when parameter is a positional parameter with more than one digit, or when parameter is followed by a character which is not to be interpreted as part of its name.
If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[#]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.
You can do this:
$ foo='bar'
$ baz='foo'
$ echo ${!baz}
bar
I have a simple question but I wonder what is the difference between ${varname} and $varname ?
I use both but I don't see any difference which could tell me when to use one or the other.
Using {} in variable names helps get rid of ambiguity while performing variable expansion.
Consider two variables var and varname. Lets see you wanted to append the string name to the variable var. You can't say $varname because that would result in the expansion of the variable varname. However, saying ${var}name would help you achieve the desired result.
$ var="This is var variable."
$ varname="This is varname variable."
$ echo $varname
This is varname variable.
$ echo ${var}name
This is var variable.name
Braces are also required when accessing any element of an array.
$ a=( foo bar baz ) # Declare an array
$ echo $a[0] # Accessing first element -- INCORRECT
foo[0]
$ echo ${a[0]} # Accessing first element -- CORRECT
foo
Quoting from info bash:
Any element of an array may be referenced using ${name[subscript]}.
The braces are required to avoid conflicts with pathname expansion.
They are the same in a basic case, but using ${varname} gives more control and ability to work with the variable. It also skips edge cases in which it can create confusion. And finally, it enables variable expansion as described in Shell Parameter Expansion:
The ‘$’ character introduces parameter expansion, command
substitution, or arithmetic expansion. The parameter name or symbol to
be expanded may be enclosed in braces, which are optional but serve to
protect the variable to be expanded from characters immediately
following it which could be interpreted as part of the name.
When braces are used, the matching ending brace is the first ‘}’ not
escaped by a backslash or within a quoted string, and not within an
embedded arithmetic expansion, command substitution, or parameter
expansion.
The basic form of parameter expansion is ${parameter}. The value of
parameter is substituted. The braces are required when parameter is a
positional parameter with more than one digit, or when parameter is
followed by a character that is not to be interpreted as part of its
name.
Let's see a basic example. Here, the use of ${} allows us to do something that a simple $ does not. Consider we want to write $myvar + "blabla"::
$ myvar=23
$ echo $myvar
23
$ echo $myvarblabla
<--- the variable $myvarblabla doesn't exist!
$ echo ${myvar}blabla
23blabla
The distinction becomes important when something follows the variable:
text="House"
plural="${text}s"
Without the braces, the shell would see texts as variable name which wouldn't work.
The braces are also necessary when you use the extended syntax to specify defaults (${name-default}), display errors when undefined (${name?error}), or pattern substitution (see this article for other patterns; it's for BASH but most work for KSH as well)
> echo $name-default
-default
> echo ${name-default}
default
Related:
Parameter Substitution in Korn-/POSIX-Shell
I have a simple question but I wonder what is the difference between ${varname} and $varname ?
I use both but I don't see any difference which could tell me when to use one or the other.
Using {} in variable names helps get rid of ambiguity while performing variable expansion.
Consider two variables var and varname. Lets see you wanted to append the string name to the variable var. You can't say $varname because that would result in the expansion of the variable varname. However, saying ${var}name would help you achieve the desired result.
$ var="This is var variable."
$ varname="This is varname variable."
$ echo $varname
This is varname variable.
$ echo ${var}name
This is var variable.name
Braces are also required when accessing any element of an array.
$ a=( foo bar baz ) # Declare an array
$ echo $a[0] # Accessing first element -- INCORRECT
foo[0]
$ echo ${a[0]} # Accessing first element -- CORRECT
foo
Quoting from info bash:
Any element of an array may be referenced using ${name[subscript]}.
The braces are required to avoid conflicts with pathname expansion.
They are the same in a basic case, but using ${varname} gives more control and ability to work with the variable. It also skips edge cases in which it can create confusion. And finally, it enables variable expansion as described in Shell Parameter Expansion:
The ‘$’ character introduces parameter expansion, command
substitution, or arithmetic expansion. The parameter name or symbol to
be expanded may be enclosed in braces, which are optional but serve to
protect the variable to be expanded from characters immediately
following it which could be interpreted as part of the name.
When braces are used, the matching ending brace is the first ‘}’ not
escaped by a backslash or within a quoted string, and not within an
embedded arithmetic expansion, command substitution, or parameter
expansion.
The basic form of parameter expansion is ${parameter}. The value of
parameter is substituted. The braces are required when parameter is a
positional parameter with more than one digit, or when parameter is
followed by a character that is not to be interpreted as part of its
name.
Let's see a basic example. Here, the use of ${} allows us to do something that a simple $ does not. Consider we want to write $myvar + "blabla"::
$ myvar=23
$ echo $myvar
23
$ echo $myvarblabla
<--- the variable $myvarblabla doesn't exist!
$ echo ${myvar}blabla
23blabla
The distinction becomes important when something follows the variable:
text="House"
plural="${text}s"
Without the braces, the shell would see texts as variable name which wouldn't work.
The braces are also necessary when you use the extended syntax to specify defaults (${name-default}), display errors when undefined (${name?error}), or pattern substitution (see this article for other patterns; it's for BASH but most work for KSH as well)
> echo $name-default
-default
> echo ${name-default}
default
Related:
Parameter Substitution in Korn-/POSIX-Shell