---
title: "Узнавать, когда длинная команда в терминале закончилась"
description: "Хватит сидеть над сорокаминутной сборкой. Одна строка после любой команды отправит результат на телефон — в том числе если вы уже ушли."
date: 2026-09-09
author: Nooc
authorAvatarLink: /images/avatars/nooc.webp
authorLink: https://nooc.me
tags:
  - терминал
  - shell
  - уведомления о сборке
  - ИИ-агенты для кода
  - вебхук-уведомления
---

# Узнавать, когда длинная команда в терминале закончилась

Вы запускаете обучение, полный набор тестов, `docker build` или ИИ-агента на длинную задачу. Дальше остаются два плохих варианта: сидеть и смотреть на полосу прогресса или уйти и вернуться через двадцать минут, чтобы узнать, что всё упало на девяностой секунде.

Есть третий вариант, и он занимает одну строку.

## Та самая строка

Создайте канал в Echobell, скопируйте его webhook-URL и допишите это после того, что запускаете:

```bash
pnpm build; curl -sS -X POST https://hook.echobell.one/t/ВАШ_ТОКЕН \
  -H 'content-type: application/json' \
  -d '{"title":"сборка завершена","body":"echobell-web"}'
```

Обратите внимание: `;`, а не `&&`. С `&&` уведомление уходит только при успехе, а это ровно наоборот — сбой как раз тот случай, о котором хочется узнать.

## Отправляйте и код возврата

Уведомление «готово» рассказывает половину истории. Захватите статус:

```bash
pnpm build; s=$?; curl -sS -X POST https://hook.echobell.one/t/ВАШ_ТОКЕН \
  -H 'content-type: application/json' \
  -d "{\"title\":\"сборка $([ $s -eq 0 ] && echo ok || echo СБОЙ)\",\"status\":\"$s\"}"
```

`s=$?` должно идти сразу после команды: что угодно между ними, включая сам тест `[`, перезапишет `$?`.

## Сделайте из этого функцию shell

Набирать такое каждый раз бессмысленно. Положите в `~/.zshrc` или `~/.bashrc`:

```bash
notify() {
  "$@"
  local status=$?
  curl -sS -X POST "$ECHOBELL_HOOK" \
    -H 'content-type: application/json' \
    -d "{\"command\":\"$*\",\"status\":\"$status\",\"host\":\"$(hostname -s)\"}" \
    >/dev/null
  return $status
}
```

Задайте `ECHOBELL_HOOK` в профиле оболочки — а лучше держите его вообще вне репозитория с дотфайлами и экспортируйте из файла, который не коммитите. Дальше:

```bash
notify pnpm test
notify cargo build --release
notify python train.py
```

Завершающее `return $status` важно: оно делает `notify` прозрачным, так что `notify make && ./deploy.sh` ведёт себя так, как вы ожидаете.

С таким payload шаблоны канала могут быть такими:

**Заголовок**

```
{{command}} · {{status}}
```

**Текст**

```
на {{host}}
```

## Звоните только при сбое

Большинство запусков проходит успешно, и слышать о них не нужно. Два канала решают это чисто: обычный для всего и звонящий с условием:

```
status != "0"
```

Направьте `notify` во второй канал для того, ради чего вы встанете с кровати, и успешные запуски останутся беззвучными.

## Пережить закрытый ноутбук и оборвавшуюся SSH-сессию

Если команда идёт по SSH, закрытый ноутбук убивает оболочку, и уведомление не уйдёт никогда. Два решения:

**tmux** — запустите команду внутри сессии и отсоединитесь:

```bash
tmux new -d -s build 'notify pnpm build'
```

**nohup** — для разового случая:

```bash
nohup bash -c 'notify pnpm build' >/dev/null 2>&1 &
```

В обоих случаях процесс переживает ваше соединение, и уведомление приходит независимо от того, подключены вы или нет.

## ИИ-агенты для кода

Та же схема покрывает CLI-агента, занятого длинной задачей:

```bash
notify codex exec "отрефактори модуль платежей и прогони тесты"
```

Для агентов, которые останавливаются посреди работы и ждут человека — согласование, запрос разрешения — уведомление о завершении не тот инструмент, ведь запуск не завершён. Этому случаю нужен собственный хук или колбэк агента, и он заслуживает скорее звонка, чем push. [Как превратить согласования агента в телефонные звонки](/ru/blog/ai-agent-human-in-the-loop-alerts) разбирает именно это, включая хук `Notification` в Claude Code и его матчер `agent_needs_input`.

Используйте оба: хук для «я застрял», функцию shell для «я закончил».

## Чего не стоит класть в уведомление

**Не вывод команды.** Соблазнительно засунуть последние строки упавшей сборки в текст. Не надо: в логах сборки токены, строки подключения и клиентские данные встречаются чаще, чем принято думать, а текст уведомления оказывается на заблокированном экране. Отправьте код возврата и идите смотреть терминал.

**Не URL канала — в публичный репозиторий дотфайлов.** Любой, у кого есть URL, может писать в ваш канал. Держите его в файле вне версионирования и включите **Только POST**, чтобы случайный предпросмотр ссылки его не запустил.

## Частые вопросы

### Почему не `terminal-notifier` или `notify-send`?

Они показывают уведомление на машине, где идёт команда. Это работает, пока вы сидите рядом. Смысл этой схемы — как раз в случае, когда не сидите: удалённая машина, закрытый ноутбук, другая комната.

### Работает ли это в Windows?

Схема да, синтаксис другой. В PowerShell эквивалент — `Invoke-RestMethod -Method Post -Uri $env:ECHOBELL_HOOK -ContentType application/json -Body $json`, а вместо `$?` используется `$LASTEXITCODE`.

### Придёт ли уведомление на часы?

Да. Подписки доставляются на сопряжённые Apple Watch, и для «сборка готова» это, честно говоря, самый уместный формат.

### А если команда идёт 12 часов?

В этой схеме ничего не истекает: `curl` выполнится, когда команда вернётся. Запускайте под tmux, чтобы обрыв связи не утащил процесс за собой.

### Могут ли коллеги получать те же уведомления?

Да. Поделитесь каналом, и каждый подписчик выберет свой тип уведомления. Удобно на общей машине для обучения, где не одному человеку важно, что GPU снова свободен.

## Итог

Одна функция shell, один канал и условие, если нужны только сбои. Настройка занимает пару минут и возвращает те двадцать, что уходят на разглядывание полос прогресса.

[Скачайте Echobell для iPhone](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-notify-when-terminal-command-finishes-ru&mt=8) или [возьмите в Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid), а потом попробуйте на чём-нибудь достаточно долгом, чтобы отойти.

---

## Связанные материалы

- [Как превратить согласования агента в звонки](/ru/blog/ai-agent-human-in-the-loop-alerts)
- [Не пропустить сбой GitHub Actions](/ru/blog/github-actions-notifications)
- [Оповещения о сбоях cron-задач](/ru/blog/cron-job-failure-alerts)
- [Документация по вебхук-триггеру](/ru/docs/webhook)
- [Справочник по условиям канала](/ru/docs/conditions)
