Yes, there is a bit of a fundamental detail about pipes there.
The point of a pipeline is to run the two or more commands in parallel, which avoids having to store all the data in full and can save time in that all processes can work at the same time. This by definition means that the second command starts before the first exits, so the exit status for the first isn't available yet.
The simple workaround is to use a temporary file instead. It shouldn't be much of a problem with storage here since we're passing just the list of file names, and not the data itself. E.g.:
tmp=$(mktemp)
if somecommand > "$tmp"; then
tar -T - -czf /tmp/someProject.tar.gz < "$tmp"
fi
rm -f "$tmp"
Or indeed like terdon comments, just let the tar
run, and remove the tar file afterwards if somecommand
failed. But if somecommand
produces a partial but significant list of files before failing, that can still cause some amount of unnecessary I/O when creating the to-be-removed archive.
Also, at least in GNU tar, by default -T
does some processing of quotes and lines that look like command line options, so if you have nasty filenames, you may need to take that into account, or look into --verbatim-files-from
, or --null
. Similar issues might exist with other tar implementations.
set -o pipefail; somecommand | tar -T - -czf /tmp/someProject.tar.gz || rm /tmp/someProject.tar.gz
? – terdon Jul 09 '21 at 12:35ifne
. – Kamil Maciorowski Jul 09 '21 at 12:54