Почему тестирование "$?" чтобы увидеть, была ли команда выполнена успешно, антипаттерн?
Я вижу здесь, что тестирование ли $? равен нулю (успех) или что-то еще (неудача) - это анти-паттерн, но я не смог найти его где-либо еще.
Придерживаясь определения анти-паттерна в Википедии: "Анти-паттерн (или анти-паттерн) является общим ответом на повторяющуюся проблему, которая обычно неэффективна и рискует быть крайне контрпродуктивной". Почему это было бы анти-паттерном?
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