Что такое код возврата

Коды возврата vs исключения — битва за контроль ошибок

Что такое ошибка?

Как видите, много всего разного и нехорошего может произойти — а ведь это далеко не полный список :). А что делать программисту? Тут, на мой взгляд, перед нами встает очень интересный и важный вопрос — как именно нашей программе реагировать на ту или иную ошибку? Пожалуй сейчас я еще раз напомню, что излагаю свое сугубо личное мнение. И скажу следующее — как именно реагировать на ошибку целиком зависит от конкретной программы. Если у нас закончилась память в драйвере — мы должны любой ценой выжить, чтобы пользователь не получил синего экрана смерти. Если же у нас закончилась память в игрушке типа веселая ферма — то имеет смысл упасть, извиниться и попросить отправить багрепорт разработчику. Системный сервис, призванный крутиться многие месяцы без перезагрузки, должен с пониманием отнестись к ошибке CreateEvent(). Та жа ошибка в прикладной программе типа Photoshop означает что скорее всего система через секунду умрет, и лучше честно упасть, нежели попытаться проглотить ошибку, дать пользователю сохранить файл и благополучно его испортить из-за последующего сбоя во время записи. Следовательно ошибки мы можем делить на ожидаемые и неожиданные. Для разных программ и разных требований одни и те же ошибки могут считаться как ожидаемыми, так и неожиданными. С ожидаемыми ошибками мы как-то работаем. Не получилось открыть файл — говорим об этом пользователю и продолжаем работу. Не удалось выделить память для загрузки туда гигабайтного файла — говорим об этом пользователю и продолжаем работу. С неожиданными ошибками мы в большинстве случаев не работаем. Закончилась память при попытке выделить двадцать байт для создания объекта — падаем. Не создался системный объект которых на всю программу три штуки — падаем. Не читается системный пайп который по спецификации должен читаться? Лучше упасть, чем оставить программу в нестабильном состоянии и потом испортить пользователю данные. Программу он если что перезапустит, а вот за испорченный файл возненавидит до конца дней своих. А для серьезных случаев есть автосейв и перезапускающий нас ежели чего watchdog.

Что было до исключений?

Через некоторое время разработчики заметили, что большинство успешных решений использует ООП и решили что неплохо бы его вынести в синтаксис языка, дабы писать больше кода по делу и меньше — повторяющегося кода для поддержки архитектуры.

Что стало после введения исключений

Давайте возьмем код выше и посмотрим, как он трансформировался после добавления ООП в синтаксис языков программирования. Конструирование и уничтожение объектов (fopen, fclose) стало конструкторами и деструкторами. Переброс неожиданной ошибки (BOOL ret в первом примере, макрос ENSURE во втором) однозначно стал исключением.

А вот с ожидаемой ошибкой случилось самое интересное — случился выбор. Можно было использовать возвращаемое значение — теперь, когда заботу о неожиданных ошибках взяли на себя исключения, возвращаемое значение снова стало в полном распоряжении программиста. А можно было использовать исключения другого типа — если функции копирования файлов самой не нужно обрабатывать ожидаемые ошибки то логично вместо if и REQUIRE просто ничего не делать — и оба типа ошибок уйдут вверх по стеку. Соответственно, у программистов снова получилось два варианта:

Почему выжили коды возврата?

Выводы

Что бы я хотел резюмировать. На мой взгляд, большинство проблем с исключениями были вызваны первыми, не очень удачными реализациями — особенно в C++. Так что выбор «использовать только коды возврата», «использовать исключения для неожиданных ошибок и коды возврата для ожидаемых» или «использовать исключения для всего» по большей части имеется только для C++. Надеюсь, мой краткий рассказ о причинах появления исключений в современных языках программирования поможет разработчикам чуть лучше ориентироваться в современных API и замечать места, где авторы использую исключения некорректно. Понимание какие из ошибок мы считаем для нашей программы ожидаемыми, какие — неожиданные и как это оптимальным образом ложится на предоставляемую языком и API модель исключений позволяет писать простой, понятный и внимательно следящий за ошибками код.

Источник

Как использовать коды завершения в Bash-скриптах

Что такое код возврата. Смотреть фото Что такое код возврата. Смотреть картинку Что такое код возврата. Картинка про Что такое код возврата. Фото Что такое код возврата

Инструменты автоматизации и мониторинга удобны тем, что разработчик может взять готовые скрипты, при необходимости адаптировать и использовать в своём проекте. Можно заметить, что в некоторых скриптах используются коды завершения (exit codes), а в других нет. О коде завершения легко забыть, но это очень полезный инструмент. Особенно важно использовать его в скриптах командной строки.

Что такое коды завершения

В Linux и других Unix-подобных операционных системах программы во время завершения могут передавать значение родительскому процессу. Это значение называется кодом завершения или состоянием завершения. В POSIX по соглашению действует стандарт: программа передаёт 0 при успешном исполнении и 1 или большее число при неудачном исполнении.

Почему это важно? Если смотреть на коды завершения в контексте скриптов для командной строки, ответ очевиден. Любой полезный Bash-скрипт неизбежно будет использоваться в других скриптах или его обернут в однострочник Bash. Это особенно актуально при использовании инструментов автоматизации типа SaltStack или инструментов мониторинга типа Nagios. Эти программы исполняют скрипт и проверяют статус завершения, чтобы определить, было ли исполнение успешным.

Кроме того, даже если вы не определяете коды завершения, они всё равно есть в ваших скриптах. Но без корректного определения кодов выхода можно столкнуться с проблемами: ложными сообщениями об успешном исполнении, которые могут повлиять на работу скрипта.

Что происходит, когда коды завершения не определены

В Linux любой код, запущенный в командной строке, имеет код завершения. Если код завершения не определён, Bash-скрипты используют код выхода последней запущенной команды. Чтобы лучше понять суть, обратите внимание на пример.

Как использовать коды завершения в Bash-скриптах

Проверяем коды завершения

После рефакторинга скрипта получаем такое поведение:

Создаём собственный код завершения

Как использовать коды завершения в командной строке

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

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

Дополнительные коды завершения

Адаптированный перевод статьи Understanding Exit Codes and how to use them in bash scripts by Benjamin Cane. Мнение администрации Хекслета может не совпадать с мнением автора оригинальной публикации.

Источник

Коды возврата & исключения

Замечательные статьи публиковались в последнее время, хотелось бы добавить ещё несколько абзацев по данной теме.

Уважаемые авторы предыдущих топиков как-то упускали тот момент (или мне показалось? или это само-собой подразумевается?) что exceptions возникли как инструмент для решения весьма утилитарной задачи — передачи управления из места возникновения ошибки в то место, где она может быть обработана.

Немного истории, чтобы понятно было, откуда такая задача возникла. В каждом более-менее нетривиальном программном обеспечении (сложнее, чем «Hello, world», да) всегда существуют точки, где нормальное выполнение не может продолжаться — I/O подсистема выдала отказ, памяти для алгоритма почему-то не хватило, входные параметры для функции ей не понравились и т.п. Как именно реагировать?

Ситуация становится ещё печальней, если рассматривать создание какой-либо библиотеки, которая должна будет использоваться в других проектах. Мы не можем (как следствие) вызывать assert/abort или ещё какую-нибудь подобный обработчик — откуда мы знаем, что имеем право завершать работу всего приложения? К примеру, наша библиотека занимается сбором какой-то статистики входных данных, а из-за такого её поведения будет остановлена работа всего устройства. А пишем мы firmware для кардиостимулятора, конечно же.

Ок, abort() — не годится. Мы не хотим создавать приложения, подобные воздушному шарику — в любом месте уколол, весь шарик умер. Мы хотим пользоваться технологией, которая позволит разделить место, где возникла ошибка, и место где принимается решение о том, что именно мы будем делать с этой ошибкой. Так как для одних применений реакцией будет запрет сбора этой статистики, для других — переинициализация библиотеки (например, с другими параметрами), где-то — просто игнорирование. Так как на более высоком уровне доступно гораздо больше информации о том, как реагировать на возникшую ошибку.

Собственно, написано это всё было для того, чтобы лучшее понимание «для чего именно» служат exceptions позволяло лучше понимать «а как их применять и для каких случаях».

PS: ещё было желание показать на примерах кода, какие именно минусы есть у exceptions. И как решалась задача «и ошибки удобно обрабатывать и exceptions при этом не использовать» (актуально для встроенных систем, когда «кардиостимуляторы» пишутся). Но это позже.

Источник

OpenSource в заметках

В статье о сигналах мы рассматривали несложный механизм, позволяющий процессам в ОС реагировать на внешние события. Рассматривались способы отправки сигналов процессам при помощи kill, а также обработка поступающих сигналов в сценариях оболочки. Аналогично сигналам, коды возврата позволяют процессам взаимодействовать с вызвавшими их процессами. Эта тема частенько игнорируется пользователями, однако довольно! Сегодня мы поговорим о кодах возврата и работе с ними.

Что такое код возврата. Смотреть фото Что такое код возврата. Смотреть картинку Что такое код возврата. Картинка про Что такое код возврата. Фото Что такое код возврата

Чем являются коды возврата

Предлагаю начать наше знакомство с простой команды известной практически каждому — mv, которая перемещает файл из одного места файловой системы в другое и, возможно, переименовывает его. Как вы уже, наверное, заметили, при работе mv могут возникать ошибки в случае, если отсутствует исходный файл, или же возникли какие-то другие обстоятельства, помешавшие mv выполнить свою работу. Например:

Вы видите сообщение об ошибке. Очевидно, что команда не сработала. И в то же самое время за кулисами оболочки инициализируется переменная оболочки, содержащая так называемый «код возврата» последней выполненной команды. При желании мы можем получить значение этой переменной. Попробуйте:

Если команда выполняется без ошибок, то обычно её код возврата равен нулю. После выполнения команды оболочка автоматически устанавливает значение переменно $? равным этому коду. Если же команда завершится с ошибкой, то, как правило, её код возврата будет отличным от нуля. В примере выше мы сперва пытаемся переместить несуществующий файл при помощи команды mv. Естественно, мы получаем ошибку, о чём свидетельствует сообщение самой программы, а также код возврата равный единице. Затем мы выполняем команду echo, которая завершается успешно. Её код возврата равен нулю.

Давайте теперь обратимся к info-странице документации программы mv (info coreutils mv). В конце документа есть абзац, говорящий о том, что нулевой код возврата команды означает успешное выполнение, а ненулевой — об ошибке. Небогатый выбор, скажем честно, негде развернуться душе сисадмина!

Вот grep предлагает более широкий выбор средств диагностики результатов своей работы. Фрагмент из документации: «Обычно нулевой код возврата означает, что искомые строки были найдены, и код равный единице в противном случае. Если же при запуске grep использовалась опция -q, —quiet или —silent, строки были найдены, но возникла какая-то ошибка, то возвращается код 2.»

Ниже приведён список определённых системных кодов возврата:

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

Использование кодов возврата

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

Оказывается, есть нюанс при работе с переменной $?, который вызван выполнением команд, вроде echo. Взгляните на результат работы сценария:

Увидели в чём проблема? Код возврата сразу после вызова mkdir равен единице, и это логично, поскольку каталог /usr существует. Но когда мы проверяем значение переменной $? в конструкции if, оказывается, что её значение равно нулю! Почему так? Потому что в этот момент значение переменной $? содержит код возврата предыдущего вызова echo, а не команды mkdir.

Получившуюся проблему можно решить, например, так:

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

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

Сокрытие сообщений об ошибках

Теперь, когда вы знаете, как анализировать код возврата программы, вы можете заменять текст сообщений об ошибках программы на свой собственный. Это можно сделать при помощи оператора >&, который перенаправляет стандартный поток вывода и поток ошибок. Например, в нашем первом простом сценарии вывод команды mkdir можно перенаправить таким образом:

Вместо >& можно с тем же успехом использовать &> или 2>&1. Конечно, если вы проверяете код возврата команды, то особого смысла в замене текста сообщений об ошибках нет.

Источник

«Код ошибки», «код возврата» и миллион терминов

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

Думал, что в баше есть только один термин- return value, который означает что программа возвращает по завершению: 0, 1 и т.д.

Но тут зашел в вики, и там куча статей по программированию и возвращаемым штукам.

Есть ли хоть какая-то разница, едрить его налево? Есть ли смысл париться?

Что такое код возврата. Смотреть фото Что такое код возврата. Смотреть картинку Что такое код возврата. Картинка про Что такое код возврата. Фото Что такое код возврата

Спасибо, добрый человек.

А не подскажешь, какой из терминов чаще в ходу?

Что такое код возврата. Смотреть фото Что такое код возврата. Смотреть картинку Что такое код возврата. Картинка про Что такое код возврата. Фото Что такое код возврата

Это несущественный вопрос, на самом деле.

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

Вот нашел еще статью.

Походу все-таки return value более традиционный термин в программировании.

Что такое код возврата. Смотреть фото Что такое код возврата. Смотреть картинку Что такое код возврата. Картинка про Что такое код возврата. Фото Что такое код возврата

return value то есть вернуть значение. Само значение же может быть и интерпретироваться тобой как угодно. Как ошибка как данные как код возврата. Это просто данные и от их значения зависит кто они и что они.

Все в ходу, но ИМХО самые толковые возвращаемое значение, код возврата и код ошибки.

В целом return code = return status = result code.

exit code это то же самое только не для функций в программе, а для самой программы

Вот и я с самого начала почувствовал некую разницу.

Cause a shell function to stop executing and return the value n to its caller. If n is not supplied, the return value is the exit status of the last command executed in the function.

Правда не понял в чем разница с exit. Вроде похожее делает.

А вот другие термины в программировании.

Хотя в контексте баша все является return value, как я понял.

А вот вижу ты дописал.

exit code это то же самое только не для функций в программе, а для самой программы

Да, exit я уже использовал, он прерывал весь скрипт. А return получается может прервать какой-то конкретный if или цикл, или другой блок программы, а дальше будет исполняться следующий?

Что такое код возврата. Смотреть фото Что такое код возврата. Смотреть картинку Что такое код возврата. Картинка про Что такое код возврата. Фото Что такое код возврата

А теперь открой для себя и потоки вывода. Если что он не один, хотя в Linux-е любят один использовать для всего.

exit делает быстрый выход и отличается от return тогда, когда вы хотите немедленно прервать работу и вернуть код ошибки, return же просто вернёт управление в вызвающую функцию. Некоторая эквивалентность имеет место только в плане взаимозаменяемости return и exit в функции main, но и то только на первый взгляд, т.к. даже main в случае с return передаст сначала управление вызвавшей её функции start, а в случае c++ также будет пытаться вызвать деструкторы.

error code это тоже return code, в том смысле что return code это любой код возврата, как успех, так и ошибка(error code).

нет, будет передано управление в функцию, которая вызвала текущую(из которой ты сделал return), т.е. она прервёт не for или if, а всю функцию или даже сценарий(когда например фунция вызвана из оболочки). Для прерывания for/if есть break и continue

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *