Странное поведение истории bash при запуске нескольких сессий

15

Как сохраняется история командной строки, когда я использую несколько окон терминала? Я знаю, что он хранится в, .bash_historyно я не вижу логики того, какая история используется, если я открываю новое окно. Это почти кажется недетерминированным в том смысле, что я никогда не знаю, какую команду я увижу, если попытаюсь использовать стрелку вверх в новом окне.

Может кто-нибудь объяснить это?

Есть ли способ контролировать историю таким образом, чтобы я мог повторно использовать историю из определенного окна?

Алекс Гительман
источник

Ответы:

14

Чтобы понять поведение истории bash, вы должны знать следующее:

  1. В файле истории есть история.
  2. В памяти процесса bash есть история.
  3. История в памяти одного процесса bash не синхронизируется с историей в памяти любого другого процесса bash.
  4. История в памяти процесса bash не синхронизируется с историей в файле, если явно не задан или во время какого-то определенного события (см. Ниже).

Используя настройки по умолчанию, жизненный цикл сеанса bash с учетом истории выглядит следующим образом:

  1. Во время запуска bash прочитает файл истории. Содержимое файла истории теперь находится в памяти процесса bash.
  2. При нормальном использовании манипулируется только история в памяти.
  3. Во время выключения история в памяти записывается в файл истории, перезаписывая любое предыдущее содержимое файла истории.

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

Прочитайте руководство по bash для более подробного объяснения процесса запуска и завершения работы.

Обратите внимание, что под настройками по умолчанию я имею в виду настройки по умолчанию из bash. Ваш дистрибутив мог предоставить .bashrc(или /etc/bash.bashrc), которые изменяют это поведение.

Включив параметр оболочки, histappendвы можете указать bash добавить вместо перезаписи файла истории. Вы можете включить histappendс помощью команды shopt -s histappend. Чтобы эта опция всегда была включена, вы должны поместить команду в свой .bashrc(или другой файл инициализации). Узнайте больше о shoptкоманде в руководстве bash

Обратите внимание, что включение histappendне сильно уменьшит кажущееся недетерминированным поведение. Это потому, что каждый сеанс bash все еще имеет свою историю в памяти. Возможно иметь в основном синхронизированную историю bash. Существует руководство, как заставить каждый процесс bash иметь синхронизированную историю в потоке при переполнении стека .

используя встроенную команду, historyвы можете явно указать bash прочитать историю из файла в память или выполнить запись из памяти в файл. Например: history -rпрочтет содержимое файла и добавит его в историю в памяти. history -wзапишет текущую историю из памяти в файл, переписав предыдущий контент. Это в основном то, что происходит во время выключения. Узнайте больше о historyкоманде в руководстве bash

Для полноты здесь приведен список внутренних переменных, которые изменяют поведение истории:

  • HISTFILE: файл для чтения и записи истории.
  • HISTFILESIZE: максимальное количество строк для файла истории.
  • HISTSIZE: максимальное количество строк для истории в памяти.
  • HISTCONTROL, HISTIGNORE, HISTTIMEFORMAT: Не имеет отношения к этой дискуссии. Прочитайте руководство bash для деталей.
lesmana
источник
Хорошее объяснение. Вы упомянули завершение работы, но как насчет уничтожения терминальной сессии? Сеанс может быть прерван через выход из системы, пользовательский интерфейс или другие средства, такие как разрыв сетевого подключения. Если весь файл истории заменен, и у вас есть несколько сеансов, вы говорите, что история из последнего закрытого будет использоваться в файле истории? Это может объяснить недетерминированное поведение.
Алекс Гительман
точка жизненного цикла (3) неверна. Кажется, что только первая сессия bash будет когда-либо записывать в файл истории. Тест: открыть 2 сеанса в порядке-а, б. Сделайте «эхо привет» в б . Затем выйдите в б . Затем откройте новый сеанс c . У этой сессии не будет эхо-приветствия в его истории.
user606723
@AlexGitelman: если процесс bash убит, у него не будет возможности перезаписать файл истории. и да, история из последнего закрытого сеанса будет той, которая будет в файле истории.
Lesmana
@ user606723: точка 3 верна. прочитайте руководство по bash. Эксперимент снова с использованием минимального .bashrcфайла. обратите внимание, что ваш дистрибутив мог изменить некоторые настройки в /etc/bash.bashrc. проверьте специально для опции оболочки histappend.
Lesmana
2

http://www.gnu.org/software/bash/manual/bashref.html#Using-History-Interactively

Вы можете быть в состоянии манипулировать тем, как файл истории записывается в один из терминалов, то есть выполнить «history -a» или «history -w» в терминале, в котором вы хотите сохранить историю, а затем «history -r» в другие терминалы. Зависит от того, что вы хотите сделать.

CJC
источник
0

AFAIK, команды bash сохраняются после завершения сеанса SSH. Таким образом, команды не сохраняются, когда сеанс завершается ненормально (например, из-за сбоя сети). Я говорю здесь о сессиях SSH. Местные терминалы могут использовать аналогичный подход.

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

Халед
источник
Это не то поведение, которое я испытал. Я могу подтвердить это, выполнив быстрый тест, где я открываю ssh-сессию, выполняю команду и выполняю изящный выход. В этом случае у меня был другой ранее активный сеанс SSH. В этой уже существующей сессии bash я проверяю .bash_history и не нахожу ничего записанного. Я считаю вероятным, что первый запущенный сеанс bash - единственный, который заканчивает запись в .bash_history.
user606723
Завершение сеанса не повлияет на текущие сеансы, но повлияет на новые сеансы!
Халед
Что если это не SSH, а окно терминала Gnome, которое я закрываю через пользовательский интерфейс?
Алекс Гительман
Это должно быть проверено. В настоящее время у меня нет доступа к терминалу Gnome!
Халед
@Khaled, протестировал, не влияет на новые сеансы. (В любом случае я проверял .bash_history, где bash получает историю команд для новых сессий, я так знал, что это не сработает, но я все равно вас расстроил.)
user606723