Десять лет в девопсе. Десять. И я гуглю tar -xzf. Не раз в год — раз в неделю. Ну, может раз в десять дней, если повезёт. Открываю хром, набираю «tar extract gz linux», пролистываю три рекламы, нахожу ответ на SO, копирую, вставляю, закрываю вкладку. Через неделю — по новой.
Я не идиот. Точнее, может и идиот, но не поэтому. Просто tar — это такой синтаксис, который у меня физически отказывается залезать в долговременную память. Там дефис или нет? xzf или xfz? Или zxf? Вроде порядок не важен? Или важен?..
Короче. Месяц назад я написал скрипт, который это решил. А потом скрипт решил больше, чем я хотел.
Я выгрузил историю хрома за последний год — ну, не целиком, отфильтровал по командной строке. Там tar extract — 47 раз. find files larger than — 31. kill process on port — 28. crontab format — 22 раза, Карл. Crontab. Я его настраиваю на каждом втором сервере.
Всего насчитал 168 запросов на вещи, которые я по идее должен знать. Ну ладно, find -exec {} \; я никогда не помнил, бог с ним, но chmod 755?
По 30 секунд на запрос (если сразу нашёл) — это полтора часа в год. Не катастрофа, да. Но раздражает неимоверно.
И я подумал — а что если просто спрашивать терминал по-русски?
Требования: ноль внешних зависимостей, потому что я не собираюсь тащить pip install на каждый прод-сервер (хотя кого я обманываю — на проде я его в итоге не поставил, но об этом позже). Любой LLM-бэкенд. И подтверждение перед выполнением — это не обсуждается.
#!/usr/bin/env python3 """ai-bash: спрашиваю по-русски — получаю bash""" import sys, os, json, urllib.request API_KEY = os.getenv("OPENAI_API_KEY", "") API_URL = os.getenv("AI_BASH_URL", "https://api.openai.com/v1/chat/completions") MODEL = os.getenv("AI_BASH_MODEL", "gpt-4o-mini") SYSTEM = ( "Ты — терминальный ассистент. Пользователь описывает задачу " "на русском языке. Отвечай ТОЛЬКО bash-командой — одной строкой. " "Без пояснений, без markdown, без обратных кавычек. " "Несколько команд — через && или |. ОС: Linux." ) def ask(question: str) -> str: body = json.dumps({ "model": MODEL, "temperature": 0, "max_tokens": 200, "messages": [ {"role": "system", "content": SYSTEM}, {"role": "user", "content": question}, ], }).encode() req = urllib.request.Request(API_URL, data=body, headers={ "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}", }) with urllib.request.urlopen(req) as r: data = json.loads(r.read()) return data["choices"][0]["message"]["content"].strip() def main(): if len(sys.argv) < 2: print("Использование: ai 'найди файлы больше 100мб'") sys.exit(1) cmd = ask(" ".join(sys.argv[1:])) print(f"\n \033[1;33m➜ {cmd}\033[0m\n") if input("Выполнить? [y/N] ").strip().lower() in ("y", "д"): os.system(cmd) if __name__ == "__main__": main()
50 строк. urllib.request — стандартная библиотека, не нужно ничего ставить. Берёт фразу, шлёт в API с промптом «ответь одной командой», показывает результат жёлтым, спрашивает «y/N». Всё.
Установка:
mkdir -p ~/bin chmod +x ~/bin/ai-bash.py echo 'alias ai="python3 ~/bin/ai-bash.py"' >> ~/.bashrc
Ключ OpenAI в .bashrc или в .env — кому как нравится. Я сначала гонял через API, потом поставил Ollama с qwen2.5:7b локально — тоже работает без изменений кода, просто меняешь переменные окружения:
export AI_BASH_URL="http://localhost:11434/v1/chat/completions" export AI_BASH_MODEL="qwen2.5:7b" export OPENAI_API_KEY="local"
На моей 3060 ответ приходит за полторы-две секунды. Не мгновенно, но быстрее, чем открыть хром.
Ну вот. ai "сколько места на диске" → df -h. ai "распакуй archive.tar.gz" → tar -xzf archive.tar.gz. ai "убей процесс на порту 8080" → kill $(lsof -t -i:8080). Нормально работает.
Самое полезное для меня оказалось вот что:
ai "переименуй все .jpeg в .jpg" → for f in *.jpeg; do mv "$f" "${f%.jpeg}.jpg"; done
Вот эта конструкция ${f%.jpeg} — parameter expansion. Я её гуглил КАЖДЫЙ раз. Каждый. Гуглил, использовал, забывал. По кругу. LLM выдаёт за секунду.
Или кронтаб. Мне нужно было ротировать логи в полночь. Я бы полез на crontab.guru, потом на SO, потом обратно на crontab.guru, потому что вечно путаю, где день недели, а где месяц. А тут — ai "crontab: ротация логов в полночь" и готово.
Кстати, не все ответы одинаково хороши. Забегая вперёд — за месяц из 847 запросов 23 раза LLM выдала фигню. Не синтаксическую ошибку — синтаксически всё валидно. А по смыслу — не то. Или опасное. Про опасное отдельно расскажу.
Ладно, скажу сразу, чтобы потом не отвечать на одно и то же в каждом втором комменте.
tldr tar — покажет примеры для tar. Но ты должен знать, что тебе нужен tar. Если ты хочешь «сделай бэкап постгреса с датой в имени файла» — тлдр тебе не поможет, потому что у тебя в голове нет слова pg_dump.
thefuck — классная штука, я ей пользуюсь до сих пор. Но она исправляет ошибку ПОСЛЕ того, как ты её допустил. Мне нужно ДО.
navi — вот тут не уверен, честно говоря. Я ставил её год назад, потыкался и забросил. Может, с тех пор стало лучше. Если кто активно пользуется — расскажите, интересно сравнить. По-моему, там каталог шаблонов, и на произвольную задачу он не ответит, но я могу ошибаться.
Copilot CLI — 10 баксов в месяц. Мой скрипт за месяц сжёг 1.80 через OpenAI API. Через Ollama — ноль.
Ну и да, мой скрипт понимает русский. Мелочь, но мне лично удобнее формулировать задачу на родном языке. Не знаю почему — скорее всего привычка, я на работе всё по-русски обсуждаю.
Вот сейчас будет ворчание не по теме, но я не могу не сказать.
Знаете, почему я гуглю, а не делаю man tar? Потому что man tar — это 800 строк, из которых мне нужны две. И они на экране 340 из 800. И я ищу их грепом по ману, что само по себе абсурд. man — гениальный инструмент, спроектированный для вдумчивого чтения на бумаге в 1971 году. Я в 2025 году в панике ищу, как распаковать архив, пока тимлид в слаке спрашивает «ну что там?».
Это не жалоба на man. Man — ОК. Это жалоба на то, что за 54 года не появилось нормальной альтернативы. Ну, tldr появился, да. Но я про это уже сказал.
Ладно, возвращаюсь к теме.
Я добавил логирование — каждый запрос пишется в ~/.ai-bash.log с таймстампом. Через 30 дней выгрузил.
847 запросов. В среднем 28 в день. По-моему, это дофига. Я не ожидал столько. Видимо, раньше часть этих задач я решал по памяти (пусть и с ошибками), а тут стал пропускать через скрипт вообще ВСЁ, вплоть до ls -la. Ну, не ls -la, конечно, но du -sh * | sort -rh — уже да.
Медианное время ответа — 0.9 сек через OpenAI, 2.1 через Ollama. Ошибочных ответов — 23 штуки, 2.7%. Три из них были реально опасные.
Стоимость API — $1.80 за месяц. По-моему, это смешно. Я на кофе из автомата больше трачу.
Самый частый запрос — «убей процесс на порту [что-нибудь]». 41 раз за месяц. Это ненормально. Это значит, что у меня что-то не так с тем, как я запускаю сервисы. Вот это, кстати, неожиданный побочный эффект — лог показал мне паттерны моей работы, которые я сам не замечал.
Но. Но-но-но.
Третья неделя. Пятница. Меня позвали починить деплой на сервере, к которому у меня ssh и больше ничего. Моего скрипта нет, Ollama нет, алиаса ai нет. Нужно распаковать архив.
Набираю tar...
И всё. Пальцы встали. -xzf? -xfz? Дефис или без? Раньше я не задумывался, просто набирал — мышечная память. А тут она пропала. Вру, не совсем пропала — я вспомнил секунд через пятнадцать. Но это были ДЛИННЫЕ пятнадцать секунд.
Я потом сел и проверил себя по десятку команд. По-честному, без гугла и скрипта. И вот что вышло (субъективно, конечно, точнее оценить сложно):
tar -xzf — раньше набирал на автомате, теперь с запинкой
find -name -exec {} \; — ну тут я и раньше не помнил, так что не считается
chmod 755 vs 644 — помню, но задумываюсь на секунду дольше
rsync -avz — помню, его я не гонял через скрипт почему-то
awk '{print $3}' — раньше мог вспомнить, сейчас нет
df -h, du -sh — помню, они слишком короткие, их я набирал руками
Получается, деградировало примерно пять из десяти. Не полностью — скорее перешло из «помню мгновенно» в «помню через 10-20 секунд» или в «не помню совсем». И закономерность такая: то, что я и раньше гуглил — не ухудшилось (нечему). То, что я набирал совсем на автомате — тоже не ухудшилось (слишком вбито в пальцы). Пострадало среднее — команды, которые я ПОЧТИ помнил.
Мозг, видимо, решил: зачем хранить то, что можно получить за секунду извне? И выкинул.
Не знаю. Честно — не знаю.
С одной стороны — я с телефонными номерами так же. Лет десять назад помнил штук двадцать наизусть. Сейчас — ноль. Мамин не помню. Ну и ладно, телефон помнит за меня, и никто не считает это деградацией.
С другой стороны... Номера телефонов — это просто данные. Десять цифр, никакого навыка. А tar -xzf — это навык. Ну, ладно, скорее микронавык. Но это способность действовать без посредника. Когда ты не помнишь мамин номер — ты не можешь позвонить маме без телефона. Когда ты не помнишь tar — ты не можешь работать без интернета.
Хотя. Если подумать. Когда я последний раз работал без интернета?
...
Ну вот. Я не могу ответить на этот вопрос, потому что не помню. Кажется, в самолёте полгода назад, и то у меня была Ollama на ноутбуке.
При этом за этот месяц я закрыл заметно больше задач. На сколько — точно не скажу, потому что месяц на месяц не приходится, может просто задачи были проще. Но ощущение такое, что каждое переключение в браузер — это маленький разрыв потока. Ты думал про деплой, полез гуглить rsync, увидел уведомление на почте, прочитал, вернулся — и три секунды вспоминаешь, что ты делал. Убрал это переключение — и поток идёт ровнее.
Скорее всего, правда где-то посередине, и я выгадал в скорости, но проиграл в автономности.
Это та часть, которую я хочу зафиксировать. Потому что эти три случая — причина, по которой строчка input("Выполнить? [y/N]") не просто UX-фича, а, без преувеличения, штука, которая спасла мне рабочий день.
Случай первый. Я пишу: «удали временные файлы». Скрипт отвечает: rm -rf /tmp/*. Казалось бы — именно то, что я просил. Но у меня в /tmp/ лежали юникс-сокеты запущенных сервисов. Я это ЗНАЛ, но забыл в момент запроса. Скрипт этого знать не мог.
Второй. «Очисти логи старше 7 дней». Ответ: find /var/log -mtime +7 -delete. Видите? Без -type f. Удалило бы директории вместе с файлами. Синтаксически идеально, по смыслу — катастрофа.
Третий. «Дай права на запись всем в текущей папке». Ответ: chmod -R 777 .. Я стоял в директории проекта. С .git. С ssh-ключами в подпапке. chmod 777 на ssh-ключи = ключи перестают работать (ssh отказывается использовать ключ с широкими правами). Это я бы чинил полчаса, и то если бы сразу понял, в чём дело.
Вывод, который я для себя сделал: скрипт экономит время на генерацию команды. Проверка — моя ответственность. Не LLM-а, не скрипта — моя. Если перестану читать то, что он мне выдаёт, перед нажатием «y» — рано или поздно словлю rm -rf или что-нибудь в этом духе.
Я потом, кстати, добавил в скрипт блеклист паттернов — rm -rf /, chmod -R 777 /, ещё пару вещей. И режим --explain, который вместо выполнения разбирает чужую команду на русском. Скрипт раздулся до 120 строк, но всё ещё стандартная библиотека, всё ещё ноль зависимостей.
Я пользуюсь этой штукой месяц. Обратно к гуглу не вернулся. По-моему, для меня лично это нетто-позитив — я быстрее работаю, меньше отвлекаюсь, меньше бешусь от рекламы на SO.
Но я соврал бы, если бы сказал, что меня не напрягает потеря мышечной памяти на tar. Напрягает. Не сильно, но где-то фоном.
Ну и главный вопрос, который я себе задаю и не могу ответить: если я за месяц разучился tar, то через год я разучусь... что? grep? awk? В какой момент я перестаю быть инженером, который использует инструмент, и становлюсь оператором, который без инструмента бесполезен?
Может, этот момент уже наступил, и я просто не заметил.
А может, это нормальная эволюция, и мои дети будут смеяться над тем, что я вообще запоминал команды — как я смеюсь над тем, что дед помнил наизусть расписание электричек.
Не знаю. Скрипт работает. tar забыл.
«Иногда пишу про такое в токены на ветер — иногда о том, как LLM думают, или просто притворяются»
UPD: Перечитал и понял, что написал «847 запросов, 28 в день» — а 847/30 это 28.2, то есть я работал без выходных. На самом деле нет, в выходные я тоже иногда дёргал терминал, просто реже. В будни было скорее 35-40, в выходные 5-10. Не то чтобы это сильно меняет суть, но для точности.
Источник


