Скрипт управляет bea на основе четырёх решений: какую книгу он читает, --json для машиночитаемого вывода, jq для нужного значения и код выхода, по которому он ветвится. Это руководство шаг за шагом проводит через эти четыре решения, а затем планирует их.
Вам нужен bea на машине, выполняющей задание, и книга, к которой он может обратиться. Если вы начинаете новые книги, сначала следуйте краткому руководству по CLI. Все факты о флагах, ключах конверта и кодах выхода ищите в справочнике по CLI Beancount, а не повторяйте здесь.
Явно выберите книгу
Назовите файл. Локальная команда разрешает свой целевой объект через --file, затем $BEA_FILE, затем ./main.bean в рабочем каталоге, и запланированное задание редко выполняется там, где вы думаете.
bea --file ~/books/main.bean check
BEA_FILE=~/books/main.bean bea check
cd ~/books && bea checkГлобальные параметры идут перед командой, например bea --file main.bean check. Если разрешённый файл не существует, команда завершается с кодом 2 и называет все три источника, так что опечатка в записи cron громко приводит к сбою, а не проверяет неправильные книги. Хостируемая адресация через флаг --ledger пока не существует; bea никогда не загружает локальный файл неявно.
Читайте JSON-конверт
Добавьте глобальный --json, и каждая поддерживаемая команда отвечает одним и тем же конвертом: bea, target, data, truncated и limit для ограниченных списков. Суммы — это десятичные строки, а даты — в ISO YYYY-MM-DD, поэтому значение безопасно сравнивать без использования числа с плавающей запятой. Ключи конверта приведены в таблице в справочнике по JSON и кодам выхода.
bea --json --file main.bean report income-statement | jq .data.net_profit
bea --json --file main.bean list transaction --limit 2 | jq '.data[0].postings[0].units'
bea --json --file main.bean import statement.csv --csv date=Date,amount=Amount,payee=Payee \
--account Assets:Checking --apply --duplicates skip | jq '.data | {written, ready, duplicates}'Эти три команды — report, list и import — сохраняют свои формы результатов, поэтому путь к jq, написанный для них, остаётся корректным. bea --json check и bea --json query также выдают конверт сегодня, но это команды, передаваемые нативным исполняемым файлам Beancount, поэтому скрипт должен опираться на статус выхода check, а не на форму его вывода. Выбирайте политику дубликатов осознанно: --duplicates по-прежнему требуется, когда импорту нужна проверка, как объясняется в прохождении импорта.
Остановитесь на правильном коде выхода
Ветвитесь по статусу и читайте объект ошибки перед любой повторной попыткой записи. В режиме --json при сбое в stdout ничего не выводится, а в stderr выводится ровно один объект, чей error.category называет класс: validation (1), usage (2), auth (3), conflict (4).
#!/usr/bin/env bash
set -euo pipefail
out=$(mktemp)
err=$(mktemp)
status=0
bea --json --file main.bean report income-statement >"$out" 2>"$err" || status=$?
case "$status" in
0) jq -r '.data.net_profit | to_entries[] | "net profit: \(.value) \(.key)"' "$out" ;;
4) echo "conflict — inspect the ledger before retrying" >&2
jq -r '.error.message' "$err" >&2
exit 4 ;;
*) jq -r '.error | "\(.category) (exit \(.exit_code)): \(.message)"' "$err" >&2
exit "$status" ;;
esacВыход 4 — это место, где скрипт никогда не должен слепо повторять попытку: это означает, что результат или конфликтный, или неизвестен, например, внешнее редактирование в момент записи или цель init, которая уже существует. Проверьте книгу, а затем повторите с нового чтения. Выход 1 охватывает ошибки проверки и любые другие ошибки выполнения; error.details содержит индивидуальные ошибки книги, а error.result — то, что фактически сделала частичная запись. Ненулевой выход никогда не гарантирует, что ничего не изменилось.
Запускайте без терминала
bea перестаёт запрашивать ввод сам. --no-input подразумевается всякий раз, когда stdin не является терминалом, когда установлен --json, и когда CI истинно — 1, true, yes или on. В этом режиме отсутствующее подтверждение приводит к сбою с кодом 2 вместо бесконечного ожидания.
CI=true BEA_NO_UPDATE_NOTIFIER=1 bea --json --file main.bean report balance-sheet
bea --json --file main.bean list transaction --limit 100 --sort oldestЧтения мягкие в терминале и строгие везде. Когда в книге есть ошибки загрузчика, query, list и report завершаются с кодом 1 при --json, при piped stdout, при истинном CI или с --strict; передайте собственный --allow-errors команды, чтобы вместо этого принять частичный ответ, что также устанавливает ledger_valid: false и заполняет ledger_errors в JSON. --strict — зеркальное отражение: он отказывает в частичных ответах даже в терминале, что вам и нужно, когда человек вручную запускает тот же скрипт. У bea check нет --allow-errors — сообщать об ошибках и есть его основная работа — и он всегда завершается с кодом 1, когда находит любые ошибки. Установите BEA_NO_UPDATE_NOTIFIER=1, чтобы отключить пассивное уведомление об обновлении; истинный CI уже делает это.
Запланируйте проверку
Запускайте проверку каждую ночь и позволяйте коду выхода быть сигналом. Оба блока ниже — это шаблоны: пути, расписание и запускающий вас.
# crontab -e — 07:15 daily; cron mails you only when bea exits nonzero
15 7 * * * BEA_NO_UPDATE_NOTIFIER=1 /opt/homebrew/bin/bea --file /home/alice/books/main.bean checkname: ledger
on:
schedule:
- cron: "15 7 * * *"
push:
jobs:
check:
runs-on: ubuntu-latest
env:
BEA_NO_UPDATE_NOTIFIER: "1"
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- run: uv tool install beancount-io==0.1.0
- run: bea --file main.bean check
- run: bea --json --file main.bean report balance-sheet > balance-sheet.jsonЗафиксируйте версию, когда задание должно быть воспроизводимым, и снимите фиксацию, когда вы предпочитаете отслеживать релизы. CI уже истинно на GitHub Actions, поэтому подсказки отключены, а уведомление об обновлении незаметно до того, как вы что-либо настроите. Здесь намеренно нет шага форматирования. Планируемое задание не должно переписывать файлы, которые ему не нужно, поэтому используйте bea format --check в pre-commit hook, который ничего не трогает и завершается с кодом 1, когда файлу требуется форматирование.
Используйте хостируемые учётные данные в задании
Установите BEA_TOKEN из хранилища секретов вашего CI-провайдера и полностью пропустите вход в браузере. Токен читается из окружения и никогда не записывается на диск, поэтому ничего не попадает в домашний каталог запускающего для следующего задания.
export BEA_TOKEN="$YOUR_CI_SECRET"
bea --json cloud statusВыход 0 означает, что учётные данные разрешены, и конверт называет учётную запись, которой они принадлежат; выход 3 с error.category со значением auth означает, что нет, и сообщение различает неустановленные учётные данные и отвергнутые. bea cloud logout ничего не делает с токеном, предоставленным таким образом — он не отзывает и не сбрасывает его, поскольку другое задание может его разделять, — поэтому отзывайте утёкший токен в панели управления. Локальным командам не нужны учётные данные вообще; только bea cloud и bea ask обращаются к хостируемому сервису. Полный список переменных находится в справочнике настроек.
Не всё отвечает в JSON. bea ask полностью отклоняет JSON-режим, bea cloud login требует человека, а успешные bea cloud logout или bea cloud ledger clone не возвращают JSON-объект успеха — читайте их статус выхода. Вывод справки, версии и автодополнения оболочки остаётся текстовым.
Следующие шаги
- Автоматизируйте банковские файлы с помощью прохождения импорта CLI.
- Найти любой флаг, ключ конверта или код выхода в справочнике по CLI Beancount.
- Обращайтесь к Python, только когда CLI исчерпан: см. скриптируемые рабочие процессы.