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"