Как стать автором
Обновить

ah — лучше, чем history

Время на прочтение 3 мин
Количество просмотров 30K
Так получается, что я провожу в консоли (терминале) достаточно времени, порой даже больше, чем хотелось бы. Порой даже исполняю там какие-то команды и внимательно изучаю их вывод. Часто случается, что к выводу той или иной команды приходится возвращаться, а он постоянно теряется: то терминалы захлопываются, то в tmux окно закрываешь, то выводы прочих команд уже давным-давно забили и похоронили ту самую полезную строчку.

Для того, чтобы сохранить вывод какой-либо утилиты я, как и многие, пользовался tee. Это работало, но постоянная суета среди бесконечных error.log, out.log, output.log, err.log log.log, lll.txt и тп если не сводила с ума, то безумно раздражала; вместо того, чтобы вести какой-то порядок, постоянно подмывало создать Новую Папку (1), где и похоронить эти самые логи, периодически бэкапя могильничек: порядок предполагал какую-то систематизацию, а в разгаре работы вспоминать как назвать свой файл крайне не хотелось.

Тогда я написал ah, крохотную утилитку, которая сильно-сильно улучшила мою жизнь.

ah предполагалась небольшим дополнением к встроенной команде history, которая есть практически в каждом шеле; однако ah умеет работать лишь с двумя: zsh (поскольку я им сам пользуюсь) и bash (поскольку им пользуются практически все, кто не пользуется zsh). Это ни в коем случае не замена history, скорее это дополнение к ней. ah, в основном, умеет 4 вещи: показывать history, сохранять вывод потоков команд, привязывать его к номеру в истории, и показывать по запросу. Кроме того, есть еще такая мелочь, как закладки (любой записи из истории можно дать имя).

Сохранение вывода команды


ah умеет сохранять объединенный вывод команды, причем каталогизацией занимается сама. В самом простейшем случае достаточно сделать вот так:

➜ ah t -- find ./app -name "*.go" -type f
./app/historyentries/get_commands.go
./app/historyentries/parser.go
./app/historyentries/keeper.go
./app/historyentries/history_entry.go
./app/historyentries/history_processor.go
./app/environments/environments.go
./app/utils/re.go
./app/utils/logging.go
./app/utils/synchronized_writer.go
./app/utils/exec.go
./app/utils/utils.go
./app/commands/bookmark.go
./app/commands/remove_bookmarks.go
./app/commands/gc.go
./app/commands/list_trace.go
./app/commands/tee.go
./app/commands/execute.go
./app/commands/show.go
./app/commands/list_bookmarks.go
./app/slices/slices.go


Вывод сохраняется (причем объединенный, как с stdout, так и с stderr), и его можно запросить в дальнейшем. В чем же отличие от, скажем, tee? С tee можно тоже написать подобное

➜ find ./app -name "*.go" -type f |& tee output.log


На самом деле, эти команды не равнозначные. Дело в том, что для tee мы перенаправляем stderr в stdout, тем самым теряя возможность их фильтрации после tee. ah же сохраняет это разделение. Иными словами, мы можем написать

➜ ah t -- find ./app -name "*.go" -type f > /dev/null


И получить на экране только вывод stderr. А что сохранит ah? Он сохранит оба потока. И код возврата. Да, ah завершается с тем же кодом, с которым отработала предыдущая команда. Еще ah нормально работает с ssh, причем даже если запускать там ncurses-приложения. Если нужно, есть поддержка псевдо-TTY и возможность запуска в реальном интерактивном шеле.

Показ истории



➜ ah s 10
...
!10109  (02.11.14 18:05:14)    nvim main.go
!10110  (02.11.14 21:48:12) *  ah t -- find ./app -name "*.go" -type f


Да, ah умеет показывать содержимое вашего HISTFILE и знает про HISTTIMEFORMAT. Угадайте, зачем рядом с номером стоят восклицательные знаки. А вот что значит звезда перед ah t...? Это значит, что ah хранит вывод этой команды. Посмотреть вывод можно с помощью субкоманды l.

➜ ah l 10110
./app/historyentries/get_commands.go
./app/historyentries/parser.go
./app/historyentries/keeper.go
./app/historyentries/history_entry.go
./app/historyentries/history_processor.go
./app/environments/environments.go
./app/utils/re.go
./app/utils/logging.go
./app/utils/synchronized_writer.go
./app/utils/exec.go
./app/utils/utils.go
./app/commands/bookmark.go
./app/commands/remove_bookmarks.go
./app/commands/gc.go
./app/commands/list_trace.go
./app/commands/tee.go
./app/commands/execute.go
./app/commands/show.go
./app/commands/list_bookmarks.go
./app/slices/slices.go


Кстати, 10 в ah s 10 означает буквально «показать последние 10 команд». В то же время поддерживается синтаксис слайсов (1:1 как в Python): ah s 10 20 покажет все команды с 11 по 20, ah s 10 _20 — с 11 по 20 с конца (_, но не -). Еще можно искать по регулярным выражениям + есть примитивный fuzzy matching.

Кроме того, можно делать закладки с субкомандой b, листать их с lb, удалять с rb, чистить старые выводы с gt, но это уже мелочи.

Надеюсь, что кому-нибудь еще жить станет легче.

So there.
github.com/9seconds/ah
Теги:
Хабы:
+89
Комментарии 21
Комментарии Комментарии 21

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн