Bash - повторно использовать вывод в каналах, если первый потребитель выходит из строя

У меня дорогая операция (curl вызов). Это может или не может произвести JSON. Если это произойдет, я хочу распечатать его, используя json_pp, Но если это не помогает, я хочу напечатать его как есть.

Вот что у меня сейчас:

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"

Соответствующая часть

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

Когда вывод JSON, все в порядке. Но когда это не так, я получаю:

искаженная строка JSON, ни массив, ни объект, ни число, ни строка, ни атом, со смещением символа 0 (до "Версия: 18.4.0, bui...") в строке /usr/bin/json_pp 45.

Я хотел бы как-то реагировать на код ошибки json_pp, так что если это не так 0, выход будет передан дальше в трубе (где cat взял бы его), но если бы он вернулся 0 (принял JSON), канал не будет продолжать (или продолжить с json_pp выходной).

Другими словами, я хочу пропустить шаг в трубе, которая терпит неудачу.
Как мне этого добиться? Ищу что-то вроде

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

Потому что все это происходит в xargs, Я ищу короткое решение, что-то вроде tee, Это может быть и функция Bash.

3 ответа

Вот что я выяснил через некоторое время после публикации:

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"'

Это работает так, как мне нужно. Спасибо за другие советы, будут полезны для более общих решений.

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

... после этого:

whatever | tryOrCat json_pp

Вывод в конвейер может быть обработан только один раз. Вам нужно будет либо скопировать его, либо сохранить. Последнее легко:

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

Это уйдет json_ppсообщение об ошибке видно. Если вы хотите скрыть это, вы можете перенаправить stderr:

json_pp <<< "$json" 2>/dev/null || printf '%s\n' "$json"
Другие вопросы по тегам