Скрипт bash: как сохранить возвращаемое значение первой команды в конвейере? - PullRequest
9 голосов
/ 10 мая 2011

Bash: я хочу запустить команду и передать результаты через какой-то фильтр, но если команда не удалась, я хочу вернуть значение ошибки команды, а не скучное возвращаемое значение фильтра:

Например:

if !(cool_command | output_filter); then handle_the_error; fi

Или:

set -e
cool_command | output_filter

В любом случае мне нужно возвращаемое значение cool_command для условия 'if' в первом случае, илидля выхода из сценария во втором случае.

Есть ли какая-то чистая идиома для этого?

Ответы [ 3 ]

15 голосов
/ 11 мая 2011

Используйте встроенную переменную PIPESTATUS.

С man bash:

PIPESTATUS

Переменная массива (см. Массивы ниже), содержащий список выхода значения статуса из процессов в самый последний выполненный передний план трубопровод (который может содержать только одиночная команда).

0 голосов
/ 11 мая 2011

Следующий скрипт использует 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
0 голосов
/ 11 мая 2011

Если вам не нужно отображать вывод ошибки команды, вы можете сделать что-то вроде

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

В этом примере error и die - это определенные функции. в другом месте в сценарии. $ 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...