This is exactly what the pipefail
runtime option is meant for:
# Make a pipeline successful only if **all** components are successful
set -o pipefail
ls /fake/folder | tee foo.txt || exit 1
If you want to be explicit about precedence, by the way, consider:
set -o pipefail
{ ls /fake/folder | tee foo.txt; } || exit 1 # same thing, but maybe more clear
...or, if you want to avoid making runtime configuration changes, you can use PIPESTATUS
to check the exit status of any individual element of the most recent pipeline:
ls /fake/folder | tee foo.txt
(( ${PIPESTATUS[0]} == 0 )) || exit
If you don't want to take any of the approaches above, but are willing to use ksh extensions adopted by bash, putting it in a process substitution rather than a pipeline will prevent tee
from impacting exit status:
ls /fake/folder > >(tee foo.txt) || exit 1