Если вы достаточно часто работаете в командной оболочке/терминале — это значит, что со временем история команд станет вашим личным хранилищем знаний, вашим справочником по командам и по документации. Возможность эффективно пользоваться этим личным хранилищем полезной информации может сильно повысить продуктивность вашего труда. Поэтому представляю вашему вниманию несколько советов относительно того, как оптимизировать настройки истории оболочки и как пользоваться этим инструментом на полную мощность.
Настройка
Я пользуюсь ZSH и Oh My Zsh, поэтому мои советы будут направлены на ZSH. Правда, почти того же, о чём рассказываю я, можно добиться и при работе с другими оболочками. Например — с Bash.
Если вы пользуетесь Bash и хотели бы перейти на ZSH, или — хотели бы попробовать выполнить примеры, показанные ниже — взгляните на эту статью.
Разобравшись с этим — начнём с настроек, которые помогут нам по полной программе задействовать сохранённую историю команд:
# ~/.zshrc
# ...
HISTFILE="$HOME/.zsh_history"
HISTSIZE=10000000
SAVEHIST=10000000
HISTORY_IGNORE="(ls|cd|pwd|exit|cd)*"
Нельзя эффективно пользоваться историей оболочки или что‑то в ней искать в том случае, если не позаботиться о хранении соответствующих данных. Использование вышеприведённых настроек приводит к тому, что храниться будет практически неограниченный объём истории команд. Эти настройки, кроме того, предусматривают использование параметра HISTORY_IGNORE
, в котором перечислены команды, записи о которых храниться не будут. Это — нечто вроде ls
, cd
и прочих подобных команд. Вы можете настроить список игнорируемых команд так, как вам нужно.
Для дальнейшей оптимизации настроек можно включить следующие опции ZSH:
# ~/.zshrc
# https://zsh.sourceforge.io/Doc/Release/Options.html (16.2.4 History)
setopt EXTENDED_HISTORY # Делать записи в файле истории в формате ':start:elapsed;command'.
setopt INC_APPEND_HISTORY # Писать данные в файл истории немедленно, а не тогда, когда осуществляется выход из оболочки.
setopt SHARE_HISTORY # Использовать во всех сессиях общее хранилище истории.
setopt HIST_IGNORE_DUPS # Не делать повторную запись о только что записанном событии.
setopt HIST_IGNORE_ALL_DUPS # Удалять старую запись о событии в том случае, если новое событие является дубликатом старого.
setopt HIST_IGNORE_SPACE # Не делать записи о командах, начинающихся с пробела.
setopt HIST_SAVE_NO_DUPS # Не записывать дубликаты событий в файл истории.
setopt HIST_VERIFY # Перед выполнением команд показывать записи о них из истории команд.
setopt APPEND_HISTORY # Добавлять записи к файлу истории (по умолчанию).
setopt HIST_NO_STORE # Не хранить записи о командах history.
setopt HIST_REDUCE_BLANKS # Убирать лишние пробелы из командных строк, добавляемых в историю.
Применение этих настроек, по большей части, направлено на то, чтобы оболочка ZSH игнорировала бы определённые команды. Это помогает предотвратить засорение истории чем‑то наподобие дубликатов команды history
. Тут, кроме того, включается запись временных меток для каждой из команд, что сделает более удобным поиск по истории (об этом мы поговорим в следующем разделе).
Мне хотелось бы особо остановиться на опции HIST_IGNORE_SPACE
, которая может оказаться очень кстати в том случае, если нужно, чтобы в истории не сохранялись бы команды, содержащие всяческие пароли и ключи доступа. Чтобы подобная команда не попала в хранилище истории — достаточно поставить перед ней пробел. Например — чтобы в историю не попала бы запись о команде вида export AWS_ACCESS_KEY_ID=...
— перед export
нужно поставить пробел.
Вышеупомянутые опции позволяют настроить то, как хранятся данные об истории команд. А теперь поговорим о том, как настроить представление истории пользователю и поиск по ней.
По умолчанию искать данные в истории команд можно только по точному совпадению. Но в ZSH имеется плагин, который позволяет осуществлять поиск данных на основе нечёткой логики. Для включения этой возможности достаточно подключить следующий плагин:
# ~/.zshrc
# ...
plugins=(git fzf)
Теперь при поиске по истории ZSH будет автоматически использовать FZF для организации нечёткого поиска. Но плагин FZF, решая свои задачи, может, в фоновом режиме, пользоваться командой find
, которая не отличается особенной быстротой. Поэтому, чтобы повысить производительность (при работе с очень большими файлами истории), я рекомендую переключить FZF на использование ag
:
sudo apt-get install silversearcher-ag
# добавить в # ~/.zshrc
export FZF_DEFAULT_COMMAND='ag --hidden -g ""'
И последняя конфигурационная опция, о которой я хочу рассказать — это форматирование временных меток. Когда пользуются командой history
, то, без дополнительных настроек, её выходные данные выглядят примерно так:
10206 echo hello
10207 head some-file.txt
10208 curl google.com
10209 cat some-file.txt
Тут мы видим номера строк из файла истории и сами команды. А вот если добавить в ~/.zshrc
опцию HIST_STAMPS="yyyy-mm-dd"
, то можно будет увидеть следующее:
10206 2024-03-30 12:29 echo hello
10207 2024-03-30 12:51 head some-file.txt
10208 2024-03-30 13:21 curl google.com
10209 2024-03-30 14:15 cat some-file.txt
Поиск
Теперь, когда мы всё настроили, поговорим о том, как эффективно искать в истории команд то, что нам нужно.
Самый простой способ поиска (когда не применяются клавиатурные привязки) заключается в использовании обычной команды history
. Правда, такой подход непрактичен, так как эта команда просто выдаст на экран всё содержимое файла с историей команд. Но можно пойти другим путём:
\history -E -10
10206 30.3.2024 12:29 echo hello
10207 30.3.2024 12:51 head some-file.txt
10208 30.3.2024 13:21 curl google.com
10209 30.3.2024 14:15 cat some-file.txt
...
\history -i
10206 2024-03-30 12:29 echo hello
10207 2024-03-30 12:51 head some-file.txt
10208 2024-03-30 13:21 curl google.com
10209 2024-03-30 14:15 cat some-file.txt
...
fc -E -l -10
10206 30.3.2024 12:29 echo hello
10207 30.3.2024 12:51 head some-file.txt
10208 30.3.2024 13:21 curl google.com
10209 30.3.2024 14:15 cat some-file.txt
...
Флаг -<N>
можно использовать для указания количества строк. Он применим и к команде history
, и к команде fc
. А флаги -E
и -i
позволяют выводить даты в разных форматах.
Для работы с историей, кроме того, можно пользоваться командой fc
без аргументов. Она может пригодиться в том случае, если нужно отредактировать или снова выполнить самую свежую команду. Эта команда открывает редактор, используемый по умолчанию. В редакторе можно отредактировать команду, а после его закрытия она будет выполнена.
Ещё одна полезная команда — это r
. Она повторно выполняет последнюю команду без редактирования (как !!
). Если вызвать её в виде r <WORD>
— будет выполнена последняя команда, содержащая строку <WORD>
.
Чаще всего, правда, поиск по истории осуществляют с использованием «горячих» клавиш. В ZSH, по умолчанию, используется клавиатурное сокращение CTRL+R
, позволяющее организовать просмотр истории с учётом контекста (виджет history):
Как видите — тут, кроме прочего, задействованы механизмы нечёткого поиска FZF.
А если по какой-то причине на вашем компьютере это не работает — проверьте у себя клавиатурные привязки:
bindkey | grep fzf-history-widget
"^R" fzf-history-widget # ^R - это CTRL+R
Если вам больше подходит классический поиск в обратном направлении, а не контекстно-ориентированный просмотр истории, тогда вы можете настроить привязки для событий
history-incremental-search-backward и history-incremental-search-forward:
# Добавить в ~/.zshrc
bindkey "^E" history-incremental-search-backward # CTRL+E
bindkey "^S" history-incremental-search-forward # CTRL+S
А ещё можно просто начать вводить команду, а потом — нажать клавишу-стрелку «вверх» или «вниз» для просмотра истории. Данные при этом будут показываться с учётом того, что введено в командной строке:
bindkey "^[[A" up-line-or-beginning-search # Стрелка вверх
bindkey "^[[B" down-line-or-beginning-search # Стрелка вниз
В документации имеются описания и других вариантов этого механизма. Например:
history-beginning-search-backward
history-beginning-search-backward-end
history-search-backward
...
Учитывайте то, что коды клавиш, применяемые в вашей ОС, могут отличаться от тех, что показаны здесь. Например — в разных системах они могут выглядеть как \e[A
, ^[OA
или ^[[A
.
Как вы, возможно, заметили на предыдущей GIF-иллюстрации, при применении классического поиска в обратном направлении можно пользоваться подсветкой синтаксиса. Для этого достаточно установить
zsh-syntax-highlighting:
sudo apt-get install zsh-syntax-highlighting
echo "source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" >> ${ZDOTDIR:-$HOME}/.zshrc
Синхронизация
Для того чтобы вывести это всё на новый уровень, чтобы ваша история команд всегда была бы с вами, даже если вы работаете на разных компьютерах — можно обратиться к плагину ZSH history-sync
. Этот плагин использует Git для синхронизации истории команд между различными рабочими станциями. Сведения о том, как он работает, и о том, как его настроить, можно найти в его документации.
Существует и более современная альтернатива history-sync
. Это — сервис atuin.sh. Он поддерживает ZSH, а в качестве хранилища данных использует SQLite. Подробности о нём вы можете найти на его сайте.
Итоги
Сейчас я практически уверен в том, что если потеряю мой файл .zsh_history
, то, возможно, не смогу больше выполнять свою работу. Я, в основном, пользуюсь командной оболочкой так: нажимаю на CTRL+R
и немного правлю то, что нахожу в истории.
Хочется надеяться, что советы, которыми я поделился, помогут вам сделать историю команд вашим личным хранилищем знаний. А это может помочь вам эффективнее работать в командной оболочке.
Здесь вы можете найти полный вариант моего файла
~/.zshrc
(с удалёнными комментариями).
О, а приходите к нам работать? ? ?
Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.
Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.
Комментарии (2)
BaJIepoH
15.04.2024 13:56Перешел на zsh как раз из-за работы с историей, когда мне не смогли выделить аккаунт для термиуса, а инвентори нужно где-то хранить.
h0tkey
Мне ещё очень пригождается
hist delete
из zsh-hist, потому что в процессе экспериментов бывают ошибочные попытки и бывают опечатки в повседневном использовании, которые совсем не хочется видеть в результатах поиска по истории.