Поймать код выхода bash в инструкции if

Если я провожу простой тест кодов выхода напрямую с помощью отдельных команд:

[user@localhost ~]$ date
Tue Sep  8 14:00:11 CEST 2020
[user@localhost ~]$ echo $?
0
[user@localhost ~]$ dat
bash: dat: command not found...
[user@localhost ~]$ echo $?
127

Но если я хочу поместить их в предложение if, я вижу, что для кода выхода 0 результат в порядке, однако для кода команды не найден (он должен быть 127) он возвращает 1.

[user@localhost ~]$ date 
Tue Sep  8 14:02:18 CEST 2020
[user@localhost ~]$ if [ $? -eq 0 ]; then   echo "Success: $?"; else   echo "Failure: $?" >&2; fi
Success: 0
[user@localhost ~]$ dat
bash: dat: command not found...
[user@localhost ~]$ if [ $? -eq 0 ]; then   echo "Success: $?"; else   echo "Failure: $?" >&2; fi
Failure: 1

Что мне не хватает?


person Zumo de Vidrio    schedule 08.09.2020    source источник
comment
Команда [ также изменяет $?. Использование: dat; status=$?; if [ $status = 0 ]; then echo "Success: $status"; else echo "Failure: $status"; fi.   -  person Jonathan Leffler    schedule 08.09.2020
comment
$? в предложении else - это статус выхода [ $? -eq 0 ] в предложении if.   -  person M. Nejat Aydin    schedule 08.09.2020
comment
@ZumodeVidrio: Мне кажется, XY-проблема. Какой у вас вариант использования? Чего ты хочешь добиться?   -  person user1934428    schedule 08.09.2020
comment
@ user1934428 Нет-нет, это вообще не проблема XY, я просто пытался добавить отладку в скрипт и хотел учесть код ошибки на случай, если это произойдет.   -  person Zumo de Vidrio    schedule 08.09.2020
comment
Тогда почему только 0 и 127? Коды больше 127 практически всегда являются ошибками, возникающими при запуске процесса, и большинство программ также используют коды от 1 (или 2) до 126 для ошибок. И почему вы хотите продолжать в случае неудачи? Разве set -e не лучше исполнит то, что вы хотите?   -  person user1934428    schedule 08.09.2020
comment
@ user1934428 127 - это просто пример, который я использовал для публикации вопроса, в моем сценарии команда (которая выполняет резервное копирование), конечно, никогда не даст 127. Мне нужно продолжить сценарий, потому что я выполняю что-то вроде: остановить службы - выполнение команды - запустить службы. Тогда, даже если команда не удалась, мне нужно будет запустить службы.   -  person Zumo de Vidrio    schedule 08.09.2020
comment
Разве это не зависит от команды в вашем скрипте? Если большинство команд в вашем скрипте не должны возвращать ненулевой код выхода, вы можете использовать set -e и явно разрешить некорректное поведение тем нескольким командам, которые вы хотите исключить. Просто идея .....   -  person user1934428    schedule 08.09.2020


Ответы (2)


У каждой команды есть собственное состояние выхода, поэтому команда [ 1 переопределит $?. Чтобы предотвратить это, сохраните код выхода в переменной и используйте его в операторе if;

le=$?
if [ "$le" -eq 0 ]; then   echo "Success: $le"; else   echo "Failure: $le" >&2; fi

Попробуйте онлайн!


1: Одиночная скобка [ на самом деле является псевдонимом для тестовой команды, а не синтаксисом. Дополнительную информацию можно найти в комментарии к unix.stackexchange.

person 0stone0    schedule 08.09.2020
comment
Я думаю, что печатать $le в случае успеха будет лишним; мы знаем, что здесь должно быть 0. - person user1934428; 08.09.2020

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

Вместо этого я бы сделал это так:

Замените существующий

command_to_verify

by

if command_to_verify
then
  echo Success
else
  echo Failure: $?
fi
person user1934428    schedule 08.09.2020