Kbool 0.1.0: классы и модули в духе Free Pascal для bash-скриптов
PrimeCoder · 2026 · формат. news
Что произошло, почему это важно и что взять в работу.
Даёт способ превратить разросшиеся bash-скрипты в поддерживаемый код с классами и модулями там, где Python недоступен, это снижает стоимость владения legacy-автоматизацией в CI и на серверах.
Связанные услуги: Лендинг под ключ, AI Boost Team, стать клиентом.
Bash-скрипт начинается с двадцати строк. Через пару лет в нём две тысячи, три десятка функций, глобальные переменные с префиксами, чтобы они не столкнулись, и source с $(dirname "$0") в начале каждого файла. Функция "возвращает" значение через stdout, значит каждый вызов обёрнут в $( ), а это fork. Fork стоит дорого, но по-другому в bash не договориться.
Переписать всё на Python можно не всегда. Скрипт живёт там, где гарантированно есть только bash и базовые утилиты. Или его поддерживают люди, которые пишут на bash. Вторая половина проблемы, про которую реже говорят, это переносимость. sed -i, stat -c, date -d, grep -Z, \b в регулярке, nc -l ведут себя по-разному на Ubuntu, на Alpine с busybox, на FreeBSD, на macOS и в Git-bash на Windows. Скрипт, который год работал на одной машине, ломается на соседней.
kbool, проект разработчика Keksov, пытается дать таким скриптам привычки Free Pascal. Модули, которые подключаются по имени через uses. Классы, объявленные как class … end, с наследованием и inherited. Библиотека классов со знакомыми именами, TStringList, TDictionary, TIniFile, TRegEx. Вышла первая версия, 0.1.0. Репозиторий открыт под MIT, CI крутится на Linux (glibc и musl), macOS, FreeBSD и Windows.
Что внутри и почему это не "ещё один обфускатор для bash"
kbool это пять git-репозиториев, корневой и четыре подмодуля. kkore держит загрузчик kk.uses, конфигурацию и обработчик ошибок. kklass реализует сами классы, поля, свойства с геттерами и сеттерами, конструкторы и деструкторы, наследование с inherited, статические члены, секции видимости. kcl это библиотека из 29 модулей, порты классов FPC и Delphi (TList, TStringList, TDictionary, TIniFile, TPath, TRegEx, DateUtils, Math), обёртки над утилитами (TGrep, TSed, TAwk, TFind, THead, TTail) и небольшой HTTP-сервер. ktests даёт тестовый фреймворк и "гейт", одну команду, которая прогоняет все наборы тестов.
Требуется bash 5.1 или новее. POSIX sh и старые bash не поддерживаются, и это честный отказ, а не тихий падёж. kbool.sh проверяет версию первым делом и выходит с кодом 2 и одной строкой в stderr, вместо того чтобы развалиться на середине загрузки в проде.
Класс объявляется в стиле паскалевского interface. Сначала структура, потом тела методов как обычные функции bash, потом build. Тела методов остаются настоящими функциями, редактор их подсвечивает, кавычки внутри строк экранировать не нужно. Внутри тела поля это обычные переменные. А func отдаёт значение в $RESULT и печатает его только внутри $( ).
У всех модулей kcl один контракт. значение возвращается в RESULT, а не в stdout; код возврата 0, успех, 1, "нет" или "не найдено" (молча, без сообщений), 2, неправильный вызов.
Вот эта строчка и есть экономика проекта. Подстановка $( ) это fork, а fork дорог. Единый контракт "значение в RESULT, код возврата как статус" убирает целый класс ошибок, где функция молча печатает в stdout, а кто-то выше ловит это в переменную и ломается на пустой строке. Модули работают под set -eu и не делают fork на горячих путях.
Наследование, uses и то, зачем это нужно на практике
Наследование выглядит так, как ожидает человек, писавший на Delphi. Объявляешь TDog. TAnimal, ставишь override, в конструкторе вызываешь inherited. Все методы виртуальные, а override это проверка при сборке, что у предка такой метод вообще есть. То есть язык ловит опечатку в имени метода до запуска, а не в момент, когда скрипт молча пошёл не туда.
Модуль подключается по имени, повторное подключение ничего не делает. kk.uses tstringlist tdictionary tinifile загружает каждый модуль один раз из пути поиска. Есть файл конфигурации и проверяемые пространства имён, а бухгалтерии вида source "$(dirname …)/…" нет. Модуль сам объявляет, от чего зависит, kk.uses tstringlist подтянет и kklass, и всё, что нужно списку.
Отклонения от FPC перечислены для каждого модуля в его README. Например, TRegEx работает на POSIX ERE из bash, а не на PCRE, поэтому ленивых квантификаторов и lookaround нет. Кто придёт из Delphi и попытается перенести сложную регулярку, споткнётся. Это не баг, это граница, и она подписана.
Демо, которое показывает цену и предел
В examples/notes.sh лежит HTTP-сервис заметок, около 175 строк кода без комментариев и пустых строк. Он показывает три модуля библиотеки и одну идею, обработчики запросов выполняются в том же процессе bash, что и сервер, поэтому объекты живут между запросами. Заметки хранятся в INI-файле через TMemIniFile, значит переживают перезапуск. Поиск ищет слово целиком, без учёта регистра, через TRegEx и \b.
Маршруты регистрируются в приложении, App.RegisterRoute /notes GET Notes.List, и дальше идёт обычная работа с объектами. Код читается как небольшой контроллер, а не как лапша из case "$1" in и глобальных переменных.
Но ограничения сервера честно записаны в README. Один запрос за раз, без keep-alive, около 10 запросов в секунду последовательно.
Ограничения сервера честно записаны в его README. один запрос за раз, без keep-alive, около 10 запросов в секунду последовательно.
Это не "bash теперь веб-сервер". Это демонстрация того, что классы и модули держат осмысленный объём кода, и одновременно напоминание, где проходит граница. Для внутреннего сервиса на десять обращений в минуту, для health-check, для локального дашборда этого хватает. Для публичного API с авторизацией и конкурентностью это мусор, и автор это не прячет.
Переносимость как главная награда
Самая полезная часть проекта для тех, кто гоняет скрипты по разным системам, это не классы. Это тесты, которые фиксируют различия. В kbool прогнали проверки через 13 конфигураций CI на каждый push в main и на каждый pull request. Там ловят разницу между mawk, gawk и busybox awk, особенности bash 5.1 вроде declare -f и unset с ключом @, и проблему десятичной запятой в локалях ru_RU и de_DE.
Последнее бьёт по самым незаметным местам. Скрипт считает awk’ом сумму, в локали ru_RU запятая вместо точки, число ломается, ошибка уходит вглубь, а на сервере с en_US всё работало годами. Единый API на Linux, macOS, FreeBSD и Windows это не маркетинговая строчка, а результат того, что эти различия выписали и прибили тестами.
Проект разработан с помощью ИИ, и в материале есть отдельный раздел про то, кто что решал, как проверялся код и какие у этого цифры. Это важно читать как процесс, а не как тезис. ИИ писал код, но контракт на RESULT, гейт из 13 конфигураций и честный README с ограничениями это работа человека, который решал, где остановиться.
Когда брать, а когда не трогать
kbool имеет смысл там, где bash уже выбран внешними обстоятельствами. Минимальный образ контейнера, где Python ставить нельзя. CI-раннер с гарантированным набором утилит. Автоматизация, которую поддерживает человек, уверенно пишущий на bash и не желающий тащить виртуальное окружение. И там, где скрипт перешёл порог в две тысячи строк и превратился в legacy, который страшно трогать.
Не имеет смысла там, где скрипт это десять строк в кронтабе. Не имеет смысла, если команда не знает bash и надеется, что паскалевский синтаксис заменит язык. И не имеет смысла для нагруженных сервисов, где 10 rps это не демо, а требование.
Требуется bash 5.1 или новее, POSIX sh и старые bash не поддерживаются. TRegEx даёт POSIX ERE, а не PCRE. Демо-сервер однопоточный и без аутентификации. Версия 0.1.0, значит API может дёрнуться, и это надо закладывать в стоимость владения.
Что это меняет для бизнеса. Legacy-автоматизация перестаёт быть долгом, который можно только переписывать. Появляется промежуточный вариант, оставить bash, но навести в нём классы, модули и единый контракт на возврат значений. Для CI и серверов, где Python недоступен, это дешевле миграции и безопаснее "дописать ещё одну функцию с префиксом".
Цена ошибки прежнего подхода простая. Скрипт, который год работал на одной машине, ломается на соседней, и никто не помнит, почему.
Артём Волков, репортёр.
PrimeCoder Team · Официальный ответ · PrimeCoder
Укажите объём тикетов в неделю и долю повторных обращений — прикинем, что измерять в первом пилоте.
Фёдор · IT
Какие логи и retention вы рекомендуете для тикетов с ПДн, чтобы не нарушать политику?