Bash переменный захват stderr и stdout отдельно или получить значение выхода

Мне нужно записать вывод и ошибку команды в моем bash script и узнать, была ли эта команда успешной или нет.

В настоящий момент я захватываю оба типа:

output=$(mycommand 2>&1)

Затем мне нужно проверить значение exit mycommand. Если это не удалось, мне нужно сделать что-то с выходом, если команда преуспела, мне не нужно касаться вывода.

Так как я фиксирую вывод, проверяя $? всегда 0, так как bash удалось захватить вывод в переменную.

Это очень чувствительный к времени script, поэтому мы стараемся избегать любых более медленных решений, таких как вывод в файл и повторное чтение.

Если бы я мог записать stdout в одну переменную и stderr в другую, это решило бы мою проблему, потому что я мог просто проверить, была ли ошибка переменной пустой или нет.

Спасибо.

Ответ 1

Какую версию bash вы используете? Захват вывода имеет нулевой эффект на код возврата с моей версией, 4.1.5:

pax> false; echo $?
1
pax> echo $?
0
pax> x=$(false 2>&1) ; echo $?
1

Не всегда хорошая идея полагаться на стандартную ошибку, непустую для обнаружения ошибок. Многие программы не выводят ошибок, но полагаются исключительно на код возврата.

Ответ 2

Проблема, по-видимому, проявляется только тогда, когда вывод записывается в локальную переменную внутри функции:

$ echo $BASH_VERSION
3.2.48(1)-release
$ false; echo $?
1
$ echo $?
0
$ x=$(false 2>&1) ; echo $?
1
$ function f {
> local x=$(false 2>&1) ; echo $?
> }
$ f
0
$ function g {
> x=$(false 2>&1) ; echo $?
> }
$ g
1

Обратите внимание, что только функция f, которая фиксирует x для локального, может выразить поведение. В частности, работает функция g, которая делает то же самое, но без "локального" ключевого слова.

Поэтому нельзя использовать локальную переменную и, возможно, "отключить" ее после использования.

EDIT. NVRAM указывает, что локальная декларация может быть сделана заранее, чтобы избежать проблемы:

$ function h {
>   local x
>   x=$(false 2>&1) ; echo $?
> }
$ h
1