Если вы достаточно часто работаете в командной оболочке/терминале — это значит, что со временем история команд станет вашим личным хранилищем знаний, вашим справочником по командам и по документации. Возможность эффективно пользоваться этим личным хранилищем полезной информации может сильно повысить продуктивность вашего труда. Поэтому представляю вашему вниманию несколько советов относительно того, как оптимизировать настройки истории оболочки и как пользоваться этим инструментом на полную мощность.

Настройка

Я пользуюсь 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):

Демонстрация нечёткого поиска по истории команд в ZSH
Демонстрация нечёткого поиска по истории команд в ZSH

Как видите — тут, кроме прочего, задействованы механизмы нечёткого поиска 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)


  1. h0tkey
    15.04.2024 13:56
    +1

    Мне ещё очень пригождается hist delete из zsh-hist, потому что в процессе экспериментов бывают ошибочные попытки и бывают опечатки в повседневном использовании, которые совсем не хочется видеть в результатах поиска по истории.


  1. BaJIepoH
    15.04.2024 13:56

    Перешел на zsh как раз из-за работы с историей, когда мне не смогли выделить аккаунт для термиуса, а инвентори нужно где-то хранить.