When to use () vs. {} in bash?

If you want the side-effects of the command list to affect your current shell, use {...}
If you want to discard any side-effects, use (...)

For example, I might use a subshell if I:

  • want to alter $IFS for a few commands, but I don't want to alter $IFS globally for the current shell
  • cd somewhere, but I don't want to change the $PWD for the current shell

It's worthwhile to note that parentheses can be used in a function definition:

  • normal usage: braces: function body executes in current shell; side-effects remain after function completes

    $ count_tmp() { cd /tmp; files=(*); echo "${#files[@]}"; }
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /tmp
    $ echo "${#files[@]}"
    11    
    
  • unusual usage: parentheses: function body executes in a subshell; side-effects disappear when subshell exits

    $ cd ; unset files
    $ count_tmp() (cd /tmp; files=(*); echo "${#files[@]}")
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /home/jackman
    $ echo "${#files[@]}"
    0
    

Documentation


From the official bash documentation:

()

( list )

Placing a list of commands between parentheses causes a subshell environment to be created, 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.

{}

{ list; }

Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. The semicolon (or newline) following list is required.


Code in '{}' is executed in the current thread/process/environment and changes are preserved, to put it more succinctly, the code is run in the current scope.
Code in '()' is run inside a separate, child process of bash that is discarded after execution. This child process is often referred to as a sub-shell and can be thought of as a new, child-like scope.

As an example consider the following...

 ~ # { test_var=test ; }
 ~ # echo $test_var
 test
 ~ # ( test_var2=test2 )
 ~ # echo $test_var2

 ~ # 

Notice in the first example with '{}' the variable is still set even after the closing '}', whereas in the example with '()' the variable is not set outside the scope of the '()'.

Also note the '{}' and '()' syntax difference. The ";" delimiter is always required for code in '{}', but not for code in '()'.


(...) are used to run code in a sub-shell. Code used bewteen {...} won't be used in a sub-shell.