Home > Net >  bash intercepting error and stop in pipeline
bash intercepting error and stop in pipeline

Time:09-23

I've been trying different things without success

so here is what I want to achieve

set -o pipefail
dump "$@" "$db" | compress | store "single" "$(backupName "$db")"

# I would want something that behaves a bit like this
# meaning if it dump fails, don't store
dump "$@" "$db" && {
  #migicGetStdout | compress | store "single" "$(backupName "$db")"
} || {
  echo failed
}

But it creates a empty file on failed dump

I'm lost with pipeline

I've tried things like

set -e
set -o pipefail

dump "${dumpCommonArgs[@]}" "${dumpDbArgs[@]}" "$@" "$db" > >(compress | store "single" "$(backupName "$db")")

# or

( compress | store "single" "$(backupName "$db")" ) < <(dump "$@" "$db") || return 2

# or 

## this way compress get the global $@ ... I don't understand that either
store "single" "$(backupName "$db")" < <(dump "${dumpCommonArgs[@]}" "${dumpDbArgs[@]}" "$@" "$db") > >(compress)


# there would be an easy one
dataToStore=$(dump "$@" "$db")
rc=$?
# but this means dump is stored in memory before saving... not the best deal as mysql already needs a lot of ram to run a dump

store function is still called!

So seems I'm missing something.

Thanks for helping me out

CodePudding user response:

You'll have to store the output of dump temporarily; example with a variable:

if out=$(dump "$@" "$db")
then
    printf '%s\n' "$out" |
    compress |
    store "single" "$(backupName "$db")"
else
    echo failed 1>&2
    exit 1
fi

or test for the emptiness of stdout (is there's no output when it fails):

dump "$@" "$db" | {
    IFS='' read -r line

    [ -n "${line: _}" ] || { echo failed 1>&2; exit 1; }

    { printf '%s\n' "$line"; cat; } |
    compress |
    store "single" "$(backupName "$db")"
}

CodePudding user response:

based on @Fravadona answer I end up writing a more generic function and thought it would be nice to share it too.

could be saved as a on-empty-return in /usr/local/bin

not forget sudo chmod x /usr/local/bin/on-empty-return

then could be used anywhere :)

#!/usr/bin/env bash
  
set -u
set -o pipefail

##
# usage
# echo "" | on-empty-return 2 cat > /tmp/should-not-create-file || {
#    >&2 echo "test failed, file is untouched (status $?)";
# }
#
# outputs to stderr
# Error: stdin is empty. (on-empty-return)
# test failed, file untouched not touched (status 2)
#
# cmd1 | on-empty-return 2 cmd2 args
# to output direct to file use cat
# cmd1 | on-empty-return 2 cat > 'file'
#
# if cmd1 output is empty, cmd2 won't be executed and will return code 2
# otherwise it'll return status code of cmd2 (assuming we have 'set -o pipefail')
#
# arg1: returned status on empty - optional default: 1
onEmptyReturn() {
  local emptyRc=1
  local re='^[0-9] $'
  [[ ${1-} =~ $re ]] && { emptyRc=$1; shift; }

  IFS='' read -r line

  [ -n "${line: _}" ] || { >&2 echo "Error: stdin is empty. ($(basename $0))"; return $emptyRc; }

  { printf '%s\n' "$line"; cat; } | "$@"

  return $?
}

onEmptyReturn "$@"

exit $?

Snippet on GitLab

  • Related