Why parentheses returns exit status but not braces

Look at the command execution trace (set -x). With braces:

+ no_func
./a: line 3: no_func: command not found
+ echo 'there is nothing'
there is nothing
+ exit 1

exit exits the (sub)shell. Since braces don't create a subshell, exit exits the main shell process, so it never reaches the point where it would run echo $?.


When you use braces, your script exits with status 1 before it reaches echo $? in the script.

Variant with subshell:

$ ./script1.sh
./script1.sh: line 3: no_func: command not found
there is nothing 
1 # <-- exit status of subshell
$ echo $?
0 # <-- exit status of script

Variant with braces:

$ ./script2.sh
./script2.sh: line 3: no_func: command not found
there is nothing # <-- the script exits with 1 after this line
$ echo $?
1 # <-- exit status of script