Q:

bash precedence with compound expression

I would like to go through a list of files and check whether they exist, giving an error and exiting if a file does not exist. I wrote the following code:
FILES=( file1.txt file2.txt file3.txt )

for file in ${FILES[@]}; do
        [ -e "${file}" ] || ( echo "ERROR: ${file} does not exist" >&2 && exit )
done

It runs without error, and yields the following (if none of the files exists):
ERROR: file1.txt does not exist
ERROR: file2.txt does not exist
ERROR: file3.txt does not exist

Why is "exit" never executed? Additionally, I would like to know the preferred way to do what I'm trying to do (control grouping with the parentheses).

A:

Might be because you run ( echo "ERROR: ${file} does not exist" >&2 && exit ) as a subprocess (your command is inside () )? So you are exiting from the subprocess.
This is a trace of your shell script (I got it with set -x):
+ FILES=(file1.txt file2.txt file3.txt)
+ for file in '${FILES[@]}'
+ '[' -e file1.txt ']'
+ echo 'ERROR: file1.txt does not exist'
ERROR: file1.txt does not exist
+ exit
+ for file in '${FILES[@]}'
+ '[' -e file2.txt ']'
+ echo 'ERROR: file2.txt does not exist'
ERROR: file2.txt does not exist
+ exit
+ for file in '${FILES[@]}'
+ '[' -e file3.txt ']'
+ echo 'ERROR: file3.txt does not exist'
ERROR: file3.txt does not exist
+ exit

This works:
set -x
FILES=( file1.txt file2.txt file3.txt )

for file in ${FILES[@]}; do
        [ -e "${file}" ] || echo "ERROR: ${file} does not exist" >&2 && exit
done

Put set -x in your file and see yourself.
Or like this
set -x
FILES=( file1.txt file2.txt file3.txt )

for file in ${FILES[@]}; do
        [ -e "${file}" ] || (echo "ERROR: ${file} does not exist" >&2) && exit
done

Update
I guess you are asking about bash - grouping Commands
This is grouping and executing in the same process
FILES=( file1.txt file2.txt file3.txt )

for file in ${FILES[@]}; do
        [ -e "${file}" ] || { echo "ERROR: ${file} does not exist" >&2; exit; }
done

This is grouping and executing in the subprocess
FILES=( file1.txt file2.txt file3.txt )

for file in ${FILES[@]}; do
        [ -e "${file}" ] || ( echo "ERROR: ${file} does not exist" >&2; exit )
done

