I believe that it's not possible
I believe that what you're asking for is not directly possible because of the way pipelines are executed. The shell does not know about the success or failure (return value) of a command when it executes "later" commands in the pipe. It literally runs all of them at the same time and collects up the results after.
There are a couple of workarounds which might help.
Workaround 1
Execute the commands one at a time and cache the results This is better because later commands absolutely will not run if an earlier command failed.
A very short script example:
cache_file=`tempfile`
if command1 > $cache_file ; then
command2 < $cache_file
fi
rm $cache_file
Workaround 2
Execute everything but check the return results This will still run all commands no matter what, but it does let you get back to find the cause.
Here each command's STDERR is redirected to a different file with 2>
. Then PIPESTATUS
is checked to find the return code of each command.
command1 2> command1_err.log | command2 2> command2_err.log
for result in ${PIPESTATUS[@]} ; do
if [ $result -ne 0 ] ; then
echo command failed
fi
done
A brief overview of running pipelines in a shell
To create the pipeline, the shell follows steps similar to these:
- The creates each pipe (
|
) using pipe(). Each pipe comes with a read handle and write handle. For each readirection (<
, >
) it opens the respective file obtaining a handle to that file using open().
- The shell calls fork() once for each command in the pipe to start a new process.
- Each child process swaps it's STDIN, STDOUT and STDERR handles for those created in (1.).
- Assuming the command is an external binary each child process then calls exec() to load and run the binary.
- The parent process then waits for the child to complete using wait() which also provides the command's return value (success or failure).
cat nonexistentfile | cat - >outfile
withoutoutfile
being created/truncated, while still getting the error fromcat nonexistentfile
? – fra-san May 09 '19 at 13:19