Bash script: как сохранить возвращаемое значение первой команды в конвейере?
Bash: Я хочу запустить команду и передать результаты через некоторый фильтр, но если команда не удалась, я хочу вернуть значение ошибки команды, а не расточное возвращаемое значение фильтра:
например:.
if !(cool_command | output_filter); then handle_the_error; fi
Или:
set -e
cool_command | output_filter
В любом случае это возвращаемое значение cool_command
, которое меня волнует - для условия "если" в первом случае, или для выхода из script во втором случае.
Есть ли какая-то чистая идиома для этого?
Ответы
Ответ 1
Используйте встроенную переменную PIPESTATUS
.
От man bash
:
PIPESTATUS
Переменная массива (см. Массивы ниже), содержащий список выходов значения статуса из процессов в самый недавно выполненный передний план трубопровода (который может содержать только одна команда).
Ответ 2
Если вам не нужно отображать вывод ошибки команды, вы можете сделать что-то вроде
if ! echo | mysql $dbcreds mysql; then
error "Could not connect to MySQL. Did you forget to add '--db-user=' or '--db-password='?"
die "Check your credentials or ensure server is running with /etc/init.d/mysqld status"
fi
В этом примере ошибки и матрицы являются определенными функциями. в другом месте в script. $dbcreds также определен, хотя он построен из параметров командной строки. Если в команде нет ошибки, ничего не возвращается. Если произошла ошибка, текст будет возвращен этой конкретной командой.
Исправьте меня, если я ошибаюсь, но у меня создается впечатление, что вы действительно хотите сделать что-то более запутанное, чем
[ `id -u` -eq '0' ] || die "Must be run as root!"
где вы фактически захватываете идентификатор пользователя до оператора if, а затем выполняете тест. Сделав это таким образом, вы можете отобразить результат, если вы выберете. Это будет
UID=`id -u`
if [ $UID -eq '0' ]; then
echo "User is root"
else
echo "User is not root"
exit 1 ##set an exit code higher than 0 if you're exiting because of an error
fi
Ответ 3
Следующий script использует fifo для фильтрации вывода в отдельном процессе. Это имеет следующие преимущества по сравнению с другими ответами. Во-первых, это не bash. В частности, он не полагается на PIPESTATUS. Во-вторых, выход не останавливается, пока команда не завершится.
$ cat >test_filter.sh <<EOF
#!/bin/sh
cmd()
{
echo $1
echo $2 >&2
return $3
}
filter()
{
while read line
do
echo "... $line"
done
}
tmpdir=$(mktemp -d)
fifo="$tmpdir"/out
mkfifo "$fifo"
filter <"$fifo" &
pid=$!
cmd a b 10 >"$fifo" 2>&1
ret=$?
wait $pid
echo exit code: $ret
rm -f "$fifo"
rmdir "$tmpdir"
EOF
$ sh ./test_filter.sh
... a
... b
exit code: 10