ah — лучше, чем history
Так получается, что я провожу в консоли (терминале) достаточно времени, порой даже больше, чем хотелось бы. Порой даже исполняю там какие-то команды и внимательно изучаю их вывод. Часто случается, что к выводу той или иной команды приходится возвращаться, а он постоянно теряется: то терминалы захлопываются, то в 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