How do I combine bash command grouping and pipe status?
This is an example command group:
{ tar -cf - my_folder 2>&1 1>&3 | grep -v "Removing leading" 1>&2; } 3>&1 | gzip --rsyncable > my_file.tar.gz
This is an example pipe status readout to go with the above:
[[ ${PIPESTATUS[*]} =~ [1-9] ]] && rm my_file.tar.gz
In this example, the command group keeps mail spool free of warnings about "Removing leading /" from tar, being delivered via cron because they land on stderr (Unices lack a stdwarn and tar lacks a quiet option), while letting real errors pass through.
The pipe status readout makes sure that corrupt backup files are immediately removed, to prevent a later cleanup using a standard FIFO algorithm from removing older valid files.
But this example does not work. In the above, the pipe status contains [1 0], that is, the exit code of grep and gzip, but not tar.
One attempt I tried was this:
{ tar -cf - my_folder 2>&1 1>&3 | grep -v "Removing leading" 1>&2; GROUPSTATUS=${PIPESTATUS[*]}; } 3>&1 | gzip --rsyncable > my_file.tar.gz
[[ $GROUPSTATUS =~ [1-9] ]] && rm my_file.tar.gz
But GROUPSTATUS is empty upon leaving the group.
(Note that by setting GROUPSTATUS to anything other than the pipe's status, eg. a literal of some sort, it can be verified that the variable does in fact escape the command grouping scope under normal circumstances.)
I've also tried if return
from within the group can deliver the first pipe component's exit code to the outside, but return inside a command group just yields an error message from bash.