18

По какой-то причине я не могу заставить мою систему сохранять историю BASH после перезагрузки. Вот соответствующие разделы моего ~/.bashrc:

shopt -s histappend
PROMPT_COMMAND='history -a; updateWindowTitle'
export HISTCONTROL=ignoredups
export HISTSIZE=9999
export HISTFILESIZE=999999
export HISTFILE="$HOME/.bash_history"

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

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

Если есть вероятность, что там будут другие релевантные команды, вы можете просмотреть весь мой ~/.bashrc здесь.

Итак, что мне не хватает? Почему моя история не сохраняется? Если кто-то думает, что другой файл может быть уместным, дайте мне знать, и я опубликую его. Я проверил, запустив grep -i hist \.* В моем $HOME который показал, что это единственно актуально . файл, содержащий hist или HIST был .bashrc .

Я использую Linux Mint Debian Edition, GNU bash, версия 4.2.36(1) -релиз (x86_64-pc-linux-gnu), и мой любимый эмулятор терминала (в случае необходимости) - terminator .


ОБНОВИТЬ:

Следуя предложению @ mpy в комментариях, я изменил свой ~/.bashrc установив HISTFILE=~/bash_history в отличие от стандартного ~/.bash_history и это, похоже, решает проблему для интерактивных оболочек. Оболочки входа в систему по-прежнему отображают то же поведение, при этом история усекается до 500 строк. Однако в соответствующих файлах не установлены переменные, связанные с HIST :

$ for f in /etc/profile ~/.profile ~/.bash_profile ~/.bash_login; do \
   echo -ne "$f :"; echo `grep HIST $f`; \
done
/etc/profile :
/home/terdon/.profile :grep: /home/terdon/.profile: No such file or directory
/home/terdon/.bash_profile :grep: /home/terdon/.bash_profile: No such file or directory
/home/terdon/.bash_login :grep: /home/terdon/.bash_login: No such file or directory
$ grep -r HIST /etc/profile.d/  <-- returns nothing

Итак, почему установки HISTSIZE и HISTFILESIZE в ~/.bashrc недостаточно, если я явно не установлю для $HISTFILE значение, отличное от значения по умолчанию ~/.bash_history?

4 ответа4

12

Проблема на самом деле сводится к разному поведению оболочек входа и не входа в систему. Я установил переменные, которые управляют историей в моем ~/.bahsrc . Этот файл не читается при запуске оболочки входа в систему, он читается только интерактивными оболочками, не входящими в систему (из man bash):

Когда bash вызывается как интерактивная оболочка входа в систему или как неинтерактивная оболочка с параметром --login , она сначала читает и выполняет команды из файла /etc/profile , если этот файл существует. После прочтения этого файла он ищет ~/.bash_profile, ~/.bash_login и ~/.profile в указанном порядке, а также читает и выполняет команды из первой, которая существует и доступна для чтения. Опция --noprofile может использоваться, когда оболочка запущена, чтобы запретить это поведение.

[. , , ]

Когда запускается интерактивная оболочка, которая не является оболочкой входа в систему, bash читает и выполняет команды из ~/.bashrc, если этот файл существует. Это может быть запрещено с помощью параметра --norc. Опция --rcfile file заставит bash читать и выполнять команды из файла вместо ~/.bashrc.

Поэтому каждый раз, когда я входил в систему, или сбрасывался в tty, или использовал ssh, файл .history потому что я также не установил его в нужном размере в ~/.profile . Я наконец понял это и просто установил переменные в ~/.profile где они принадлежат, вместо ~/.bashrc

Итак, причина, по которой моя ~/.history была усечена, заключалась в том, что я установил только переменные HISTORY в файле, читаемом интерактивными оболочками, не входящими в систему, и поэтому каждый раз, когда я запускал оболочку другого типа, переменные игнорировались, и файл будет вырезан соответственно.

9

Я предлагаю использовать другой файл в качестве HISTFILE , а не файл по умолчанию ~/.bash_history .

Хотя у меня нет аналитического объяснения, я попытаюсь обрисовать, что привело меня к этому предложению: если вы используете bash качестве оболочки по умолчанию (login), а также используете X (что очень вероятно), у вас сразу же работает запущенный экземпляр bash (графический) логин:

systemd
 ...
  |-login
  |   `-bash      <<====
  |       `-slim
  |           |-X -nolisten tcp vt07 -auth /var/run/slim.auth
  |           |  `-{X}
  |           `-fluxbox
  |               `-xterm -bg black -fg white
  |                   `-bash
 ...

Я думаю, что этот экземпляр является оболочкой входа в систему, поэтому он не читает ваш ~/.bashrc и, следовательно, не будет ничего знать о параметре histappend :

man bash(1): Когда запускается интерактивная оболочка, которая не является оболочкой входа в систему , bash читает и выполняет команды из /etc/bash.bashrc и ~ /.bashrc, если эти файлы существуют. (...)

Пока эта "родительская оболочка" работает, все в порядке, но после ее завершения (т.е. остановки системы) она переопределит ~/.bash_history (потому что это значение по умолчанию) и испортит вашу историю или обрезает ее при запуске системы ( снова по умолчанию) 500 строк. (Или, возможно, оба ...)

Мне также кажется, что недостаточно включить конфигурацию истории в ~/.bashrc , так как это не должно быть такой необычной установкой. У меня нет объяснения этому.


Что касается вашей проблемы, что «Оболочки входа в систему по-прежнему отображают то же поведение», вы можете попробовать включить конфигурацию истории также в ~/.bash_profile:

man bash(1): Когда bash вызывается как интерактивная оболочка входа в систему или как неинтерактивная оболочка с параметром --login, она сначала читает и выполняет команды из файла /etc /profile, если этот файл существует. После прочтения этого файла он ищет ~ /.bash_profile, (...)

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

2

Поскольку все ваши настройки в порядке в соответствии с man-страницей, а файл истории не ограничен размером (в байтах), я могу придумать единственное возможное объяснение. Это связано с тем, как оболочка умирает.

Согласно онлайн-справке, постепенный выход (сохраненная история) происходит только тогда, когда оболочка получает сигнал SIGHUP. Я не могу объяснить, как ваша система передает сигналы при перезагрузке, но я подозреваю, что ваша оболочка закрывается с SIGKILL или SIGPWR.

Это может быть из-за того, что ваш WM работает асинхронно (ожидание), и эмулятор терминала, порожденный от WM, где bash получает сигнал форсирования выхода, отличный от SIGHUP. Может также случиться так, что ОС должна быстро отправить "окончательное уничтожение" всем процессам, прежде чем начальному грациозному SIGHUP удастся добраться до оболочки через X -> WM -> xterm, возможно, потому что X или WM требует больше времени для выхода, чем требуется, чтобы ОС была готова к выходу из строя.

Я нахожусь в глубоких водах с этим материалом, но я думаю, что что-то в этом роде вызывает беспорядочное поведение. У меня была эта проблема раньше, и самое надежное средство - это exit в bash, где вы хотите сохранить историю.

Я заметил history -a в вашем вопросе, и я не могу думать о том, почему этого было бы недостаточно, чтобы сохранить историю.

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

trap "echo got 1  >/tmp/sig1;  exit" SIGHUP
trap "echo got 2  >/tmp/sig2;  exit" SIGINT
trap "echo got 15 >/tmp/sig15; exit" SIGTERM
 .. and so on...

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

человек баш

На старте, (...) Файл, названный значением HISTFILE, усекается, если необходимо, чтобы он содержал не более количества строк, указанных значением HISTFILESIZE (+ по умолчанию 500).

Если включена опция оболочки histappend (+ по умолчанию здесь), строки добавляются в файл истории, в противном случае файл истории перезаписывается.

онлайн ссылка

3.7.6 Сигналы

Когда Bash является интерактивным, в отсутствие каких-либо ловушек он игнорирует SIGTERM (так что «kill 0» не уничтожает интерактивную оболочку), а SIGINT перехватывается и обрабатывается (так, чтобы встроенная функция ожидания была прерываемой). Когда Bash получает SIGINT, он прерывает выполнение любых циклов. Во всех случаях Bash игнорирует SIGQUIT. Если контроль заданий действует (см. Контроль заданий), Bash игнорирует SIGTTIN, SIGTTOU и SIGTSTP.

Для не встроенных команд, запускаемых Bash, в обработчиках сигналов установлены значения, унаследованные оболочкой от ее родителя. Когда управление заданиями не действует, асинхронные команды игнорируют SIGINT и SIGQUIT в дополнение к этим унаследованным обработчикам. Команды, выполняемые в результате подстановки команд, игнорируют генерируемые клавиатурой сигналы управления заданиями SIGTTIN, SIGTTOU и SIGTSTP.

Оболочка выходит по умолчанию при получении SIGHUP. Перед выходом интерактивная оболочка отправляет SIGHUP всем работам, запущенным или остановленным. Остановленные задания отправляются SIGCONT, чтобы гарантировать получение SIGHUP. Чтобы предотвратить отправку оболочкой сигнала SIGHUP на конкретное задание, его следует удалить из таблицы заданий с помощью встроенной функции disown (см. Раздел «Встроенные элементы управления заданиями») или пометить, чтобы она не получала SIGHUP с помощью команды disown -h.

Если параметр оболочки huponexit был установлен с помощью shopt (см. Построение магазина), Bash отправляет SIGHUP всем работам при выходе из интерактивной оболочки входа.

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

демонстративный снимок экрана

сигналы

0

Проверьте /etc /profile и /etc/profile.d/*

Может быть, там что-то не так с настройками истории.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .