15%

Сэкономьте 15% на всех хостинговых услугах

Проверьте свои навыки и получите скидку на любой тарифный план

Используйте код:

Skills
Начать
09.10.2024

Команда `history` в Linux: Полное руководство по истории Bash

Команда `history` в Linux — это встроенная утилита оболочки Bash, которая записывает, отображает и управляет каждой командой, выполненной в сеансе терминала. Она считывает данные из `~/.bash_history` и записывает в него — простой текстовый файл в домашнем каталоге каждого пользователя, позволяя вам вспоминать, искать, повторно выполнять и проверять команды между сеансами без необходимости их повторного ввода.

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

Как работает история Bash изнутри

Когда вы открываете сеанс терминала, Bash загружает содержимое `~/.bash_history` в список в памяти. По мере выполнения команд они добавляются в этот буфер в памяти. Когда сеанс завершается нормально (через `exit` или `logout`), буфер сбрасывается обратно в `~/.bash_history` в соответствии с правилами, определёнными переменными среды.

Эта архитектура имеет важное следствие: если ваш сеанс завершается аварийно (отключение питания, разрыв SSH-соединения, `kill -9`), команды из этого сеанса могут никогда не быть записаны на диск. Это распространённый источник путаницы, когда администраторы теряют след команд, выполненных во время прерванного сеанса.

Два параметра оболочки изменяют это поведение записи при выходе по умолчанию:

  • `shopt -s histappend` — добавляет новую историю в `~/.bash_history` вместо её перезаписи. Это необходимо в многосеансовых средах.
  • `PROMPT_COMMAND='history -a'` — заставляет Bash добавлять последнюю команду в файл истории после каждого приглашения, обеспечивая сохранение в реальном времени и видимость между терминалами.

Без `histappend` побеждает последняя закрытая оболочка — она перезаписывает файл истории, молча удаляя записи из всех остальных параллельных сеансов.

Основы использования команды `history`

Отображение полной истории команд

“`bash

history

“`

Выводит пронумерованный список сохранённых команд. Число слева — это индекс истории, используемый для обозначения событий.

Отображение определённого количества последних команд

“`bash

history 20

“`

Показывает последние 20 команд. Удобно, когда нужно быстро просмотреть недавнюю активность без прокрутки сотен записей.

Немедленная запись истории текущего сеанса в файл

“`bash

history -w

“`

Принудительно записывает буфер истории из памяти в `~/.bash_history`. Используйте это перед закрытием важного сеанса, чтобы ничего не потерять.

Чтение истории из файла в текущий сеанс

“`bash

history -r

“`

Перезагружает `~/.bash_history` в память текущего сеанса. Удобно, когда нужно получить доступ к командам, введённым в другом окне терминала в рамках того же входа в систему.

Вызов и повторное выполнение команд

Обозначения событий с `!`

Синтаксис обозначения событий в Bash позволяет напрямую повторно выполнять исторические команды по ссылке:

ОбозначениеПоведение
`!!`Повторно выполняет непосредственно предшествующую команду
`!n`Выполняет команду с индексом истории `n`
`!-n`Выполняет команду, отстоящую на `n` позиций назад от текущей
`!string`Выполняет последнюю команду, начинающуюся с `string`
`!?string?`Выполняет последнюю команду, содержащую `string` в любом месте
`!$`Подставляет последний аргумент предыдущей команды
`!*`Подставляет все аргументы предыдущей команды

Практический пример — повторное использование последнего аргумента:

“`bash

mkdir /var/www/myproject

cd !$

“`

`!$` раскрывается в `/var/www/myproject`, избавляя вас от необходимости повторно вводить путь. Это одна из наиболее недооценённых, но высокоэффективных возможностей истории Bash.

Предварительный просмотр перед выполнением:

Добавьте `:p` к любому обозначению события, чтобы вывести команду без её выполнения:

“`bash

!42:p

“`

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

Обозначения слов для извлечения аргументов

Помимо повторного выполнения целых команд, Bash позволяет извлекать конкретные аргументы из записей истории:

“`bash

!!:2 # Second word (argument) of the last command

!!:1-3 # Words 1 through 3 of the last command

!ssh:$ # Last argument of the most recent ssh command

“`

Такая степень детализации неоценима при построении сложных конвейеров или повторении операций с одними и теми же путями к файлам.

Сочетания клавиш для навигации по истории

Сочетание клавишДействие
`Up Arrow` / `Ctrl+P`Перейти к предыдущей команде
`Down Arrow` / `Ctrl+N`Перейти к следующей команде
`Ctrl+R`Инкрементальный поиск в обратном направлении по истории
`Ctrl+S`Инкрементальный поиск вперёд (требует `stty -ixon`)
`Alt+.`Вставить последний аргумент предыдущей команды
`Ctrl+G`Отменить текущий поиск по истории

Примечание о `Ctrl+S`: По умолчанию `Ctrl+S` активирует управление потоком XON/XOFF и замораживает терминал. Чтобы включить поиск по истории вперёд, добавьте `stty -ixon` в ваш `~/.bashrc`.

Поиск в обратном направлении с помощью `Ctrl+R`

“`

(reverse-i-search)`git': git commit -am "fix: resolve race condition"

“`

Введите подстроку, и Bash инкрементально найдёт последнюю команду, содержащую её. Нажмите `Ctrl+R` ещё раз для перехода к более старым совпадениям. Нажмите `Enter` для выполнения или `Ctrl+G` для отмены без запуска чего-либо.

Для поиска по большому объёму истории используйте перенаправление через `grep`:

“`bash

history | grep "docker run"

history | grep -E "^[[:space:]]+[0-9]+[[:space:]]+ssh"

“`

Редактирование записей истории и управление ими

Удаление конкретной записи

“`bash

history -d 87

“`

Удаляет команду с индексом 87 из списка в памяти. Чтобы сделать это постоянным, выполните `history -w` для записи изменённого списка обратно на диск.

Удаление диапазона записей

“`bash

for i in $(seq 85 90); do history -d 85; done

“`

Поскольку удаление смещает индексы, всегда удаляйте один и тот же номер индекса в цикле, а не увеличивайте его.

Очистка всей истории в памяти

“`bash

history -c

“`

Очищает буфер истории текущего сеанса. Это не затрагивает `~/.bash_history` на диске.

Полное удаление всей истории

“`bash

history -c && history -w

“`

Очищает буфер в памяти, а затем записывает пустой буфер в `~/.bash_history`, фактически усекая файл. Это правильная двухшаговая последовательность — использование только `> ~/.bash_history` не очищает буфер в памяти, поэтому файл может быть заново заполнен при завершении сеанса.

Настройка истории Bash: переменные среды

Всё поведение истории управляется переменными среды, обычно задаваемыми в `~/.bashrc` (интерактивные оболочки без входа в систему) или `~/.bash_profile` / `~/.profile` (оболочки с входом в систему). Изменения вступают в силу после применения файла:

“`bash

source ~/.bashrc

“`

`HISTSIZE`

Управляет количеством команд, хранящихся в памяти во время активного сеанса.

“`bash

export HISTSIZE=10000

“`

Установка значения `0` полностью отключает историю в памяти. Установка значения `-1` (в Bash 4.3+) делает её неограниченной.

`HISTFILESIZE`

Управляет максимальным количеством строк, хранящихся в `~/.bash_history` на диске.

“`bash

export HISTFILESIZE=20000

“`

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

`HISTCONTROL`

Определяет правила фильтрации для записываемых команд.

ЗначениеПоведение
`ignoredups`Пропускает последовательные дублирующиеся команды
`ignorespace`Пропускает команды с пробелом в начале
`ignoreboth`Объединяет оба вышеуказанных правила
`erasedups`Удаляет все предыдущие вхождения команды перед добавлением новой

“`bash

export HISTCONTROL=ignoreboth

“`

Применение `ignorespace` в целях безопасности: Добавьте пробел перед любой командой, содержащей пароль или секрет, чтобы предотвратить её запись:

“`bash

mysql -u root -pSuperSecretPassword

“`

Это широко используемая практика операционной безопасности на общих или многопользовательских системах.

`HISTTIMEFORMAT`

Добавляет метку времени к каждой записи истории, сохраняемой в виде строки комментария в `~/.bash_history`.

“`bash

export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "

“`

Пример вывода:

“`

487 2024-11-14 09:32:17 systemctl restart nginx

488 2024-11-14 09:32:45 tail -f /var/log/nginx/error.log

“`

Метки времени необходимы для криминалистического анализа после инцидентов в средах VPS Хостинга и выделенной инфраструктуре. Без них вы знаете *что* было выполнено, но не *когда*.

`HISTIGNORE`

Разделённый двоеточиями список шаблонов glob. Команды, соответствующие любому шаблону, не сохраняются в истории.

“`bash

export HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:history"

“`

Это предотвращает засорение истории тривиальными командами и снижение качества результатов поиска. Вы также можете использовать подстановочные знаки:

“`bash

export HISTIGNORE="*password*:*secret*:*token*"

“`

Это мера глубокой защиты — сочетайте её с `ignorespace` для максимальной защиты учётных данных.

Полная справочная таблица переменных конфигурации истории Bash

ПеременнаяПо умолчаниюНазначение
`HISTSIZE`500–1000Команды, хранящиеся в памяти за сеанс
`HISTFILESIZE`500–2000Строки, хранящиеся в `~/.bash_history`
`HISTCONTROL`(не задано)Правила фильтрации для записываемых команд
`HISTTIMEFORMAT`(не задано)Формат метки времени, добавляемой перед записями
`HISTIGNORE`(не задано)Шаблоны glob для исключаемых команд
`HISTFILE``~/.bash_history`Путь к файлу истории
`histappend` (shopt)выкл.Добавление вместо перезаписи при завершении сеанса

Совместное использование истории в нескольких сеансах терминала

По умолчанию каждый сеанс Bash поддерживает собственный изолированный буфер истории. Команды, введённые в терминале A, невидимы для терминала B до тех пор, пока оба сеанса не закроются и файл не будет записан. Для администраторов, управляющих несколькими SSH-сеансами одновременно на Выделенных серверах, это создаёт пробелы в операционных записях.

Рекомендуемая конфигурация для совместного использования истории между сеансами в реальном времени:

“`bash

~/.bashrc

export HISTSIZE=100000

export HISTFILESIZE=100000

export HISTCONTROL=ignoreboth

export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "

shopt -s histappend

PROMPT_COMMAND='history -a; history -c; history -r'

“`

Что это делает:

  • `history -a` — добавляет последнюю команду в файл
  • `history -c` — очищает буфер в памяти
  • `history -r` — перезагружает файл в память

После каждой команды каждый сеанс терминала видит полную, единую историю из всех активных сеансов. Компромисс — незначительные накладные расходы на выполнение `PROMPT_COMMAND`, которые на практике пренебрежимо малы.

Эффективный поиск по истории: продвинутые техники

`fzf` — нечёткий поиск по истории

Инструмент `fzf` превращает поиск по истории из линейного сканирования в интерактивный интерфейс нечёткого поиска:

“`bash

Install fzf (Debian/Ubuntu)

sudo apt install fzf

Bind Ctrl+R to fzf-powered history search

Add to ~/.bashrc:

[ -f ~/.fzf.bash ] && source ~/.fzf.bash

“`

После настройки `Ctrl+R` открывает полноэкранный нечёткий поиск по всей вашей истории. Это особенно эффективно при работе с большими файлами истории (более 10 000 записей), где `grep` становится неудобным.

Извлечение истории для написания скриптов

“`bash

Export all unique commands containing "iptables" to a script

history | grep iptables | awk '{$1=""; print $0}' | sort -u > iptables_audit.sh

“`

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

Соображения безопасности для истории Bash

История Bash — это инструмент с двойным назначением. Она ускоряет законные рабочие процессы, но также представляет значительную поверхность атаки.

Ключевые риски и меры по их снижению:

  • Раскрытие учётных данных: Пароли, передаваемые в качестве аргументов командной строки (например, `curl -u admin:password`), хранятся в открытом виде в `~/.bash_history`. Вместо этого используйте `ignorespace`, `HISTIGNORE` или переменные среды.
  • Криминалистика повышения привилегий: Злоумышленники, получившие доступ к оболочке, регулярно читают `~/.bash_history` для изучения среды, обнаружения учётных данных и выявления ценных целей. Установите ограничительные права доступа: `chmod 600 ~/.bash_history`.
  • Подделка истории: Скомпрометированный пользователь может выполнить `history -c && history -w` для уничтожения всех улик. В целях аудита на производственных системах рассмотрите возможность ведения журнала команд на основе `auditd` или `syslog`, которые не могут быть изменены пользователем.
  • Изоляция истории root: История суперпользователя хранится в `/root/.bash_history`. Убедитесь, что этот файл недоступен для чтения другими пользователями и включён в область резервного копирования и аудита.

Для сред, требующих строгого аудита команд — таких как инфраструктура, соответствующая PCI-DSS или SOC 2, — одной истории Bash недостаточно. Дополните её аудитом на уровне ядра через `auditd` и централизованной отправкой журналов.

История Bash в сравнении с альтернативными системами истории оболочки

ФункцияИстория BashИстория ZshИстория Fish
Файл истории по умолчанию`~/.bash_history``~/.zsh_history``~/.local/share/fish/fish_history`
Поддержка меток времениЧерез `HISTTIMEFORMAT`ВстроеннаяВстроенная (формат YAML)
Обработка дубликатовПараметр `HISTCONTROL`Параметр `HIST_IGNORE_DUPS`Автоматическое удаление дубликатов
Совместное использование между сеансамиРучное (`PROMPT_COMMAND`)Параметр `INC_APPEND_HISTORY`Автоматическое (общее по умолчанию)
Интерфейс поиска`Ctrl+R` (линейный)`Ctrl+R` (линейный)С подсветкой синтаксиса, контекстно-зависимый
Максимальный размер историиПеременная `HISTFILESIZE`Переменная `SAVEHIST`Без жёсткого ограничения
Механизм блокировкиОтсутствует (возможны состояния гонки)Поддерживается блокировка файловНа основе SQLite (атомарная запись)

Основное ограничение истории Bash — отсутствие встроенной блокировки, что может вызывать состояния гонки при одновременной записи из нескольких сеансов. Zsh и Fish решают эту проблему более изящно на уровне оболочки.

Практическая конфигурация для производственных сред

Ниже приведена проверенная конфигурация истории `~/.bashrc`, подходящая для производственных Linux-серверов, включая те, на которых работает VPS с cPanel или пользовательскими панелями управления:

“`bash

— Bash History Configuration —

export HISTSIZE=50000

export HISTFILESIZE=50000

export HISTCONTROL=ignoreboth:erasedups

export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "

export HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:bg:fg:jobs"

export HISTFILE=~/.bash_history

Append to history file; don't overwrite

shopt -s histappend

Save and reload history after each command

PROMPT_COMMAND='history -a; history -c; history -r'

Enable multi-line command history as single entry

shopt -s cmdhist

Store multi-line commands with embedded newlines

shopt -s lithist

“`

`cmdhist` и `lithist` заслуживают особого упоминания. Без `cmdhist` многострочная команда (например, цикл `for`, введённый интерактивно) сохраняется как отдельные строки, что делает невозможным её чистое повторное выполнение. При включённом `cmdhist` и заданном `lithist` вся конструкция сохраняется как единая запись истории с буквальными символами новой строки, сохраняя её структуру.

Автоматизация рабочих процессов на основе истории

Создание отчёта о частоте использования команд

“`bash

history | awk '{print $2}' | sort | uniq -c | sort -rn | head -20

“`

Это показывает 20 наиболее часто используемых вами команд — полезно для выявления кандидатов на создание псевдонимов или функций оболочки.

Аудит использования `sudo`

“`bash

history | grep sudo | awk '{$1=""; print $0}'

“`

В средах с Панелями управления VPS это обеспечивает быстрый аудит привилегированных операций, выполненных в течение сеанса.

Восстановление хронологии сеанса

“`bash

HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S " history | grep "2024-11-14"

“`

Фильтрует все команды, выполненные в определённую дату — неоценимо при анализе после инцидентов.

Ключевые технические выводы и контрольный список решений

Перед развёртыванием конфигурации истории Bash в любой среде проверьте следующее:

  • `shopt -s histappend` задан — предотвращает потерю истории из-за перезаписи параллельными сеансами
  • `HISTSIZE` и `HISTFILESIZE` оба настроены — установка только одного оставляет другой со значением по умолчанию, вызывая неожиданное усечение
  • `HISTTIMEFORMAT` включён — без меток времени история не имеет криминалистической ценности
  • `HISTCONTROL=ignoreboth` задан как минимум — снижает шум и предотвращает запись команд, связанных с учётными данными
  • `HISTIGNORE` исключает тривиальные команды — поддерживает высокое соотношение сигнал/шум в истории
  • `~/.bash_history` имеет `chmod 600` — предотвращает чтение истории команд другими пользователями
  • `cmdhist` включён — обеспечивает хранение многострочных команд как единых блоков
  • `PROMPT_COMMAND` синхронизирует историю в реальном времени — необходимо для многосеансовых сред
  • `auditd` развёрнут совместно — для производственных систем, где требуется защищённое от подделки ведение журнала
  • Учётные данные никогда не передаются как аргументы CLI — используйте переменные среды, `.netrc` или менеджеры секретов

Часто задаваемые вопросы

Почему история Bash исчезает после закрытия SSH-сеанса?

Обычно это происходит потому, что `shopt -s histappend` не задан. Без него каждый сеанс перезаписывает `~/.bash_history` при выходе. Если сеанс завершается аварийно (разрыв сети, `kill -9`), запись вообще не происходит. Задайте `histappend` и `PROMPT_COMMAND='history -a'` для сохранения команд в реальном времени.

Как предотвратить сохранение паролей в истории Bash?

Используйте два взаимодополняющих метода: добавьте пробел перед командой (требует `HISTCONTROL=ignorespace` или `ignoreboth`) и добавьте шаблоны конфиденциальных команд в `HISTIGNORE`. Для долгосрочной гигиены никогда не передавайте секреты как аргументы CLI — используйте переменные среды или специализированные инструменты управления секретами.

В чём разница между `HISTSIZE` и `HISTFILESIZE`?

`HISTSIZE` управляет количеством команд, которые Bash хранит в памяти во время активного сеанса. `HISTFILESIZE` управляет количеством строк, сохраняемых в `~/.bash_history` на диске. Оба должны быть заданы явно — большое значение `HISTSIZE` при малом `HISTFILESIZE` означает, что история в сеансе богатая, но большая её часть удаляется при завершении сеанса.

Можно ли восстановить удалённые записи истории?

После выполнения `history -c && history -w` буфер в памяти очищается, а файл усекается — стандартное восстановление невозможно. Однако если ваша система использует снимки файловой системы или решения для резервного копирования, предыдущая версия `~/.bash_history` может быть восстановлена из снимка. Это ещё одна причина внедрить `auditd` для защищённого от подделки ведения журнала на критической инфраструктуре.

Как совместно использовать историю Bash в нескольких одновременных сеансах терминала?

Добавьте следующее в `~/.bashrc`: `shopt -s histappend` и `PROMPT_COMMAND='history -a; history -c; history -r'`. Это заставляет каждый сеанс добавлять последнюю команду в общий файл и перезагружать полный файл после каждого приглашения, предоставляя всем активным терминалам единое представление истории команд в реальном времени.

15%

Сэкономьте 15% на всех хостинговых услугах

Проверьте свои навыки и получите скидку на любой тарифный план

Используйте код:

Skills
Начать