If you have something like this:
#!/bin/bash
(
x=foo
{ echo $x }
)
What is the significance of the parentheses and braces? What are these constructs known as? What properties do they have? What are they used for etc.?
If you have something like this:
#!/bin/bash
(
x=foo
{ echo $x }
)
What is the significance of the parentheses and braces? What are these constructs known as? What properties do they have? What are they used for etc.?
The commands enclosed in round parentheses (...) are run in a subshell. They inherit the environment from the parent shell, but any changes they make isn't propagated back to the parent.
{ echo $x } is wrong, there's a missing ; before the closing }. Commands run in { ... } are run in the context of the current shell, it's usually used when you need to redirect output of several commands, e.g.
{
echo 1
echo 2
} > log
Note that the final ; is not needed if there's a newline in its place.
re: the (curly) braces ({...}) ... from the man pages for bash:
{ list; } list is simply executed in the current shell environment. list must be termi‐ nated with a newline or semicolon. This is known as a group command. The return status is the exit status of list. Note that unlike the metacharacters ( and ), { and } are reserved words and must occur where a reserved word is permitted to be recognized. Since they do not cause a word break, they must be separated from list by whitespace or another shell metacharacter.
The provided example of a single command inside braces ({ echo $x }), setting aside the syntax issue, doesn't make much sense (ie, it's not any different than echo $x).
$ { echo "I found all these PNGs:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls; } > PNGs.txt
# or
$ { echo "I found all these PNGs:"
find . -iname "*.png"
echo "Within this bunch of files:"
ls
} > PNGs.txt
Here the {...} groups all of the output together so that only a single > PNGs.txt is required to send the output from all 4x commands to the file PNGs.txt.
Without the {...} you would need:
$ echo "I found all these PNGs:" > PNGs.txt
$ find . -iname "*.png" >> PNGs.txt
$ echo "Within this bunch of files:" >> PNGs.txt
$ ls >> PNGs.txt
For the following set of commands the (...) and {...} generate the same result (all output sent to file PNGs.txt) ...
{ echo "I found all these PNGs:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls; } > PNGs.txt
( echo "I found all these PNGs:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls; ) > PNGs.txt
... with the 2nd option incurring the additional overhead of spawning a subshell.
With the following example we see the different effects of execution in the current/parent shell vs execution in the subshell:
$ { x=5 ; } # defined in current/parent shell
$ ( x=7 ; ) # defined in subshell, not visible to parent; `;` is optional
$ echo $x
5