is there a better way than the following code to prefix the output of a command but still being able to check its return value?
command > "$tmpfile" 2>&1
ret=$?
sed 's/^/ | /' "$tmpfile"
if [[ ! "$ret" -eq 0 ]]; then
rm "$tmpfile"
exit 1
fi
With bash and a few other shells, you can use the pipefail option, which when enabled causes the exit status of a pipeline to be that of the rightmost component that failed as opposed to the rightmost component:
(set -o pipefail; cmd | sed 's/^/ | /') || exit
Another option is to redirect stdout to a process substitution instead of using a pipe:
cmd > >(sed 's/^/ | /') || exit
Though beware that sed which in that case is started in background and is not waited for, may not have finished writing by the time the next command is run.
Specific to bash, there's the $PIPESTATUS special array (zsh has a $pipestatus equivalent) which records the exit status of every component in a pipeline:
cmd | sed 's/^/ | /'; ret=${PIPESTATUS[0]}
[ "$ret" -eq 0 ] || exit "$ret"
POSIXly, you can do:
{
ret=$(
exec 4>&1
{
cmd 3>&- 4>&-
echo "$?" >&4
} | sed 's/^/ | /' >&3 3>&- 4>&-
)
} 3>&1
[ "$ret" -eq 0 ] || exit "$ret"
You could use a helper function:
prefix() (
prefix=$1; shift
exit "$(
exec 4>&1
{
"$@" 3>&- 4>&-
echo "$?" >&4 3>&- 4>&-
} | PREFIX=$prefix awk '{print ENVIRON["PREFIX"] $0}' >&3 3>&- 4>&-
)"
) 3>&1
prefix ' | ' cmd
(here switching to awk so as to be able to use arbitrary prefixes.
if command | sed...
– gcomte
Jun 11 '20 at 12:47
&&sed||rm (but this won't work for exit 1) – alecxs Jun 11 '20 at 07:38ret=${PIPESTATUS[0]}is perfectly complete and obviates the need for a temp file altogether, but I'll just add that if you do use a temp file, the better way to remove it is via atrap, e.g.,traprm -f "$tmpfile"EXIThttps://unix.stackexchange.com/questions/480330/temporary-folder-that-automatically-destroyed-after-process-exit – michael Jun 11 '20 at 08:17