Bash отвергает число 08: ведущие нули и десятичная арифметика
Номер месяца из имени отчёта приходит как 08. Скрипт должен прибавить единицу, но арифметика Bash отвечает value too great for base. С январём всё работало, поэтому ошибка появляется только летом. Причина в синтаксисе числовых констант: ведущий ноль задаёт восьмеричную систему, в которой цифр 8 и 9 нет.
Удалить ноль вручную из одного имени недостаточно. На вход может прийти 00, пустая строка или вообще выражение. Полезно разделить два действия: подтвердить формат поля и затем явно выбрать основание числа. Для номера месяца допустимы ровно две десятичные цифры от 01 до 12.
Нормализуем поле на границе
В примере функция получает один аргумент, проверяет его вид и диапазон, затем печатает число без ведущего нуля. Ошибки идут в stderr, чтобы результат можно было безопасно получить подстановкой команды.
#!/usr/bin/env bash
month_number() {
if [[ $# -ne 1 || ! $1 =~ ^[0-9]{2}$ ]]; then
printf 'Expected a two-digit month
' >&2
return 2
fi
local month=$((10#$1))
if ((month < 1 || month > 12)); then
printf 'Month out of range
' >&2
return 2
fi
printf '%d
' "$month"
}
for raw in 01 08 09 12; do
value=$(month_number "$raw") || exit 1
printf '%s -> %d
' "$raw" "$value"
done
if month_number 00 >/dev/null 2>&1; then exit 1; fi
if month_number '1+1' >/dev/null 2>&1; then exit 1; fi
Получатся пары 01 → 1, 08 → 8, 09 → 9 и 12 → 12. Префикс 10# явно задаёт десятичное основание. Поскольку перед арифметикой разрешены только две цифры, строка не может стать произвольным арифметическим выражением.
Ограничение длины здесь имеет смысл: месяц по договору всегда двухзначный. Для другого поля выберите собственный максимальный размер и проверьте переполнение. Арифметика оболочки выполняется целыми фиксированной разрядности; она не предназначена для денег с дробной частью или произвольно больших идентификаторов.
Когда число должно остаться строкой
Номер заказа 0008 обычно нельзя превращать в 8: ведущие нули могут быть частью идентификатора. Если поле только сравнивается, передаётся в API или участвует в имени файла, сохраняйте его исходную строку. Преобразование оправдано, когда действительно нужна арифметическая величина.
Для печати месяца обратно с двумя цифрами используйте printf '%02d' с уже нормализованным значением. Ширина вывода и основание исходного числа — разные вопросы. Форматирование не исправляет неверно разобранное значение.
Проверим опасную границу
После успешных примеров попробуйте 00, 13, пустую строку, знак минус, пробел и выражение 1+1. Все они должны завершаться ненулевым статусом до вычисления. Если внешний источник начинает присылать однозначный месяц, сначала измените контракт и проверки, затем регулярное выражение.
Такая небольшая функция полезна в скрипте разбора имён архивов или каталогов выгрузки. Она отделяет ошибку данных от ошибки вычисления: сообщение о неверном месяце понятнее, чем ошибка основания где-то в середине длинного сценария. Храните эти граничные примеры рядом с функцией, чтобы следующая правка не вернула сезонную поломку.
Для следующих скриптов пригодятся условия, функции и правила передачи значений. Эти темы входят в курс Bash Linux + Git вместе с практическими задачами. Посмотрите программу и научитесь проверять вход до выполнения команд.
Продолжить на практике
- Bash Linux + Git: от новичка до уверенного пользователя ↗
Освоим два важнейших инструмента разработчика: применение bash-скриптов в практических задачах и git в его самых разных проявлениях.
