简体   繁体   中英

Bash - reuse the output in pipes if the first consumer fails

I have an expensive operation ( curl call). This may or may not produce JSON. If it does, I want to pretty print it using json_pp . But if that fails, I want to print it as-is.

This is what I have now:

filter "$ENVI" "$2" running | dns_ \
   | xargs  -L1 --max-args=1 -I{} $DEBUG_XARGS --no-run-if-empty \
   sh -c "echo 'Versions at {}': ; curl --fail http://... | json_pp"

The relevant part is

curl --fail http://... | json_pp

When the output is JSON, it's ok. But when it's not, I get:

malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "Version: 18.4.0, bui...") at /usr/bin/json_pp line 45.

I would like to somehow react to the error code of json_pp , so that if it is not 0 , the output would be passed further in the pipe (where cat would take it), but if it returned 0 (accepted the JSON), the pipe would not continue (or continue with json_pp 's output).

In other words, I want to skip the step in the pipe which fails.
How can I achieve this? Looking for something like

curl --fail http://... | ifTheFollowingFailsThenPassAsIsOtherwiseUseOutputOf json_pp | cat

Because it all happens in xargs , I am looking for a short solution, something like tee . It may be a Bash function, too.

tryOrCat() {
  local input output
  input=$(cat) || return
  if output=$("$@" <<<"$input"); then
    printf '%s\n' "$output"
  else
    printf '%s\n' "$input"
  fi
}

...thereafter:

whatever | tryOrCat json_pp

Here's what I figured out a while after posting:

bbTmp=$(mktemp "${TMPDIR:-/tmp}/bbPp.XXXXXX")
export bbTmp # to be available to sh -c

filter "$ENVI" "$2" running | dns_ | xargs  -L1 --max-args=1 -I{} --no-run-if-empty \
  sh -c 'curl --fail http://{}/... | tee "$bbTmp" | json_pp 2>/dev/null || cat "$bbTmp"'

This works just as I need. Thanks for the other tips, will be useful for more generic solutions.

Output in a pipeline can only be processed once. You'll need to either duplicate it or save it. The latter is easy:

json=$(curl --fail http://...)
json_pp <<< "$json" || printf '%s\n' "$json"

This will leave json_pp 's error message visible. If you want to hide it you can redirect stderr:

json_pp <<< "$json" 2>/dev/null || printf '%s\n' "$json"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM