Как устроены коды выхода
Каждый процесс завершается с 8-битным статусом от 0 до 255. По соглашению 0 означает успех, а всё остальное — ошибку; shell показывает его как $?, и &&, ||, if и set -e ветвятся по нему. Значение числа помимо «ноль/не ноль» определяет сама программа, но есть несколько почти универсальных соглашений.
Собственные коды shell
- 126: файл найден, но не может быть выполнен. Отсутствует бит выполнения, это каталог, бинарник для другой архитектуры или раздел, смонтированный с
noexec. - 127: не найден. Опечатка, программа не установлена или
PATHотличается между вашей оболочкой и окружением, в котором выполняется скрипт (cron, systemd, Docker). Также строка shebang, указывающая на отсутствующий интерпретатор, включая окончания строк\r\n, превращающие путь в/bin/bash\r. - 128 + n: процесс погиб от сигнала n. Shell не может вернуть сигнал напрямую, поэтому добавляет 128. 130 — это Ctrl-C (SIGINT 2), 137 — SIGKILL (9), 139 — SIGSEGV (11), 143 — SIGTERM (15). Справочник сигналов перечисляет их все.
137 в контейнерах
Код 137 из контейнера — почти всегда OOM killer ядра или среда выполнения контейнера, применяющая лимит памяти: процессу отправлен SIGKILL, который нельзя перехватить, поэтому приложение ничего не записало в лог. Проверьте docker inspect на OOMKilled: true, dmesg на «Out of memory» или события Kubernetes на OOMKilled. 143 — нормальный результат docker stop или завершения пода, когда процесс обработал SIGTERM; 137 после остановки означает, что он не завершился в отведённый период.
sysexits.h
BSD определила коды 64–78, чтобы почтовые и системные утилиты сообщали категории ошибок (EX_USAGE 64, EX_NOINPUT 66, EX_TEMPFAIL 75…). Postfix, sendmail и некоторые программы на Perl и Go всё ещё их используют; больше никто, поэтому относитесь к ним как к соглашению, а не правилу.
Вопросы
Что означает код выхода 1?
Общая ошибка: программа решила, что что-то пошло не так, и не имела более конкретного кода. Для grep он означает, что ни одна строка не совпала, что вовсе не ошибка. Читайте вывод программы в stderr, а не число.
Почему я получаю 127 в cron или systemd, но не в своей оболочке?
PATH отличается. Профиль вашей оболочки добавляет каталоги вроде /usr/local/bin или ~/.local/bin, которых cron и systemd не видят. Используйте абсолютные пути или задайте PATH в начале скрипта.
Какой максимальный код выхода?
255. exit 256 превращается в 0, exit 300 становится 44 (300 mod 256). Отрицательные значения тоже заворачиваются: exit(-1) — это 255.
Как получить код выхода конвейера?
По умолчанию $? — статус последней команды. set -o pipefail заставляет конвейер завершиться с ошибкой, если упал любой этап, а массив PIPESTATUS в bash хранит код каждого этапа.