Почему тестирование "$?" чтобы увидеть, была ли команда выполнена успешно, антипаттерн?

Я вижу здесь, что тестирование ли $? равен нулю (успех) или что-то еще (неудача) - это анти-паттерн, но я не смог найти его где-либо еще.

Придерживаясь определения анти-паттерна в Википедии: "Анти-паттерн (или анти-паттерн) является общим ответом на повторяющуюся проблему, которая обычно неэффективна и рискует быть крайне контрпродуктивной". Почему это было бы анти-паттерном?

2 ответа

Решение

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

if your_command; then ...

гораздо меньше ошибиться, чем

your_command
if [ "$?" -eq 0 ]; then ...

Примеры вещей, которые могут пойти не так: подумайте о ловушках или даже о новых echo операторы добавлены для отладки, модификации $?, Для читателя не очевидно, что работает отдельная строка your_command ниже ничего не может быть добавлено без изменения логического потока.

То есть:

your_command
echo "Finished running your_command" >&2
if [ "$?" -eq 0 ]; then ...

... проверяет эхо, а не фактическую команду.


Таким образом, в тех случаях, когда вам действительно нужно иметь дело со статусом выхода более детально, чем сразу же указывать, равно ли его значение нулю, вы должны собрать его в одной строке:

# whitelisting a nonzero value for an example of when "if your_command" won't do.
your_command; your_command_retval=$?
echo "Finished running your_command" >&2 ## now, adding more logging won't break the logic.
case $your_command_retval in
  0|2) echo "your_command exited in an acceptable way" >&2;;
  *)   echo "your_command exited in an unacceptable way" >&2;;
esac

Наконец: если вы приложите your_command внутри if Это означает, что это означает, что ваша оболочка не будет рассматривать ненулевой статус выхода для целей set -e или ERR ловушка.

Таким образом:

set -e
your_command
if [ "$?" -eq 0 ]; then ...

... никогда не будет (за исключением ряда угловых случаев и предостережений, которые чумы set -e Поведение if заявление с любым значением $? Кроме как 0 как set -e заставит выход в этом случае. В отличие от:

set -e
if your_command; then ...

... отмечает статус выхода your_command как проверено, и поэтому не считает, что это заставляет скрипт завершать работу set -e,

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

Если нам нужно возвращаемое значение функции и код выхода, другого пути нет (или я этого не знаю, поправьте меня, если я ошибаюсь). В приведенном ниже примере нам нужно продолжить, только если предыдущая команда была успешной, и мы используем возвращаемое значение в другой функции.

Пример:

      test() { echo "A" ; return 1; }
l_value=$(test); l_exit_code=$?;

if (( l_exit_code == 0 )); then
   fn_other_function_to_pass_value $l_value
else
   echo "ERROR" >&2
   exit 1
fi
Другие вопросы по тегам