История команд в терминале — инструмент для повышения продуктивности

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

Конфигурация

В статье используется ZSH и Oh My Zsh, советы будут сосредоточены на ZSH, но аналогичных результатов можно добиться и для Bash или других оболочек.

Начнем с вариантов конфигурации, которые помогут максимально эффективно использовать сохраненную историю.
# ~/.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      # Write the history file in the ':start:elapsed;command' format.
setopt INC_APPEND_HISTORY    # Write to the history file immediately, not when the shell exits.
setopt SHARE_HISTORY         # Share history between all sessions.
setopt HIST_IGNORE_DUPS      # Do not record an event that was just recorded again.
setopt HIST_IGNORE_ALL_DUPS  # Delete an old recorded event if a new event is a duplicate.
setopt HIST_IGNORE_SPACE     # Do not record an event starting with a space.
setopt HIST_SAVE_NO_DUPS     # Do not write a duplicate event to the history file.
setopt HIST_VERIFY           # Do not execute immediately upon history expansion.
setopt APPEND_HISTORY        # append to history file (Default)
setopt HIST_NO_STORE         # Don't store history commands
setopt HIST_REDUCE_BLANKS    # Remove superfluous blanks from each command line being added to the history.

Настройки выше в основном конфигурируют ZSH, чтобы игнорировать определенные команды и избегать засорения истории, например, дубликатами или командами истории. Они также добавляют временные метки к каждой команде, что будет полезно при поиске (см. следующий раздел).


Одна особая опция, на которую стоит обратить внимание, — это HIST_IGNORE_SPACE, которая может быть полезна, если вы хотите избежать хранения секретов в истории. Просто добавьте пробел перед любой командой, которая включает в себя секрет/пароль, например, export AWS_ACCESS_KEY_ID=... (обратите внимание на пробел перед export), и она не появится в истории.


Теперь расскажем о том, как настроить поиск и отображение истории.


По умолчанию вы можете искать только по точному совпадению, но в ZSH есть плагин, который позволяет использовать нечеткий поиск. Чтобы включить его, нам просто нужно добавить плагин:

# ~/.zshrc
# ...

plugins=(git fzf)

ZSH автоматически будет использовать FZF для нечеткого поиска. Однако, возможно, команда find будет использоваться в фоновом режиме, что не очень быстро. Чтобы улучшить производительность (для очень больших файлов истории), рекомендуем использовать ag:

sudo apt-get install silversearcher-ag

# add to # ~/.zshrc
export FZF_DEFAULT_COMMAND='ag --hidden -g ""'

И последняя опция конфигурации, о которой стоит упомянуть, — форматирование временных меток истории. По умолчанию, когда вы просматриваете историю, вы получите вывод вида:

10206  echo hello
10207  head some-file.txt
10208  curl google.com
10209  cat some-file.txt

Это — номер строки из файла истории и сама команда. Однако, добавив HIST_STAMPS="yyyy-mm-dd" в ~/.zshrc, мы можем получить следующее:

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 по умолчанию предоставляет прокручивание истории на основе контекста (виджет истории).

Как видите, это также включает нечеткий поиск FZF.


Если по какой-то причине это не работает на вашей машине, проверьте привязки клавиш:

bindkey | grep fzf-history-widget

"^R" fzf-history-widget  # ^R is CTRL+R

Если вы предпочитаете классический обратный поиск вместо прокрутки истории на основе контекста, тогда вы можете привязать события history-incremental-search-backward и history-incremental-search-forward:

# Add to ~/.zshrc
bindkey "^E" history-incremental-search-backward  # CTRL+E
bindkey "^S" history-incremental-search-forward   # CTRL+S

Вы также можете просто начать вводить команду и нажимать стрелки вверх/вниз для поиска по истории, учитывая то, что уже введено в командной строке.

bindkey "^[[A" up-line-or-beginning-search    # Arrow up
bindkey "^[[B" down-line-or-beginning-search  # Arrow down

В документации также есть другие варианты, например:

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 для синхронизации истории между рабочими станциями — смотрите документацию плагина, чтобы понять, как он работает и как его настроить.


Более современная альтернатива вышеуказанной функции синхронизации — atuin.sh, который использует SQLite в качестве хранилища и поддерживает ZSH.

Заключение

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


Примечание: Полный ~/.zshrc (без комментариев) можно найти здесь.