You are mixing three different usages of parentheses in Bash: array definition, command substitution, and command grouping. Command substitution and command grouping are standard syntaxes and all POSIX sh
-like shells support them. The array definition syntax is supported in shells that additionally have arrays.
Array Definition
Arrays are assigned to using compound assignments of the form
name=(value1 value2 … )
Your a=($x)
creates an array with a single element, whose value is the value specified by $x
, i.e. 1
. When you echo an array by its name, in your case echo $a
, it only echoes the first element of the array. So that's what you see, a 1
is printed to stdout.
If you have multiple elements in an array you can use "${arrayname[*]}"
or "${arrayname[@]}"
to access them. The first combines all array elements into a single argument while the second put each element as an individual argument.
This syntax is specific to bash
and to other shells that allows for arrays in a similar way.
Command substitution (POSIX)
Command substitution allows the output of a command to replace the
command itself. Command substitution occurs when a command is enclosed
as follows:
$(command)
Your command $(echo foo)
performs shell substitution and is parsed to foo
. So it is the same as you have typed foo
. Since the command foo
does not exist, bash complains about it.
Command grouping (POSIX)
Bash provides two ways to group a list of commands to be executed as a
unit. When commands are grouped, redirections may be applied to the
entire command list. For example, the output of all the commands in
the list may be redirected to a single stream.
( list )
Placing a list of commands between parentheses causes a
subshell environment to be created (see Command Execution
Environment), and each of the commands in list to be executed in that
subshell. Since the list is executed in a subshell, variable
assignments do not remain in effect after the subshell completes.
Your command (echo foo)
executes echo foo
in a subshell, so foo
is echoed. This has nothing to do with the command substitution. As the manual says, variable assignments in subshell do not remain in effect after the subshell completes. This can come handy if you want to write simple one-liners. For example, instead of
for l in {1..10}; do mycommand "$l"; done; unset l
You can write,
( for l in {1..10}; do mycommand "$l"; done )
Another helpful usage of a subshell is like using
( cd folder; ./mycommand )
instead of
cd folder; ./mycommand; cd -
Your command echo ($x)
falls into none of these three categories, and bash
reports a syntax error.
Quote your variables properly
It is also worth mentioning that you should quote your variable expansions whenever applicable (for example, when a string should contain the value of a variable). See When is double-quoting necessary? for details.
For example, the following would not invoke the particular constructs described above:
x=1
a="($x)"
echo "$a"
echo "($x)"
Here, both calls to echo
would output (1)
.
Links to bash
manual pages
https://www.gnu.org/software/bash/manual/html_node/Command-Grouping.html
https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html
https://www.gnu.org/software/bash/manual/html_node/Arrays.html
a="($x)"
is very different from the one in the question,a=($x)
– ilkkachu Mar 21 '19 at 12:30