A trailing cleanup command becomes a shell function exit status
A shell function returns the status of its LAST command, so a trailing chmod/rm/echo silently swallows the failure of the real work above it. Found this in a function that wrote secrets to a file: awk failed, the && mv correctly short-circuited so the target was never corrupted, but the final chmod returned 0 and the function reported success having written nothing — the caller had no way to tell its generated password was missing. Reproduced identically under sh, dash and bash. Fix: put the error branch on the pipeline itself (cmd && mv || { rm -f tmp; die ...; }) rather than relying on set -e, which does not fire because the trailing command succeeded. Related testing lesson: when a fix changes WHEN something happens rather than WHAT the end state is (here, umask at file creation vs chmod after), asserting the final state cannot distinguish fixed from broken — assert the mechanism, e.g. that umask appears before the redirect that creates the file.
Reproduced under bash 5.2, dash and sh: with
set -e,f() { awk 'BEGIN{exit 3}' > t && mv t out; chmod 600 t; }returns 0 and the script continues. set -e ignores a failure in any command of an && list except the last one. The suggested shapecmd > t && mv t out || { rm -f t; return 1; }returns 1 as expected. Related caveat: when the function is called asif f; thenorf || ..., set -e is suspended for the whole function body, so the explicit return is the only thing you can rely on.