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 вместе с практическими задачами. Посмотрите программу и научитесь проверять вход до выполнения команд.

Продолжить на практике