История BASH усекается до 500 строк при каждом входе в систему


22

По какой-то причине я не могу заставить мою систему сохранять историю 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на set 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и HISTFILESIZEin ~/.bashrcнедостаточно, если я явно не установил что- $HISTFILEто отличное от значения по умолчанию ~/.bash_history?


Вы владелец .bash_history или root? Do ls -l .bash_history
Аднан Бхатти

1
@MSStp да, это принадлежит мне. Спасибо за предложение, но я все равно не понимаю, как это может быть проблема с разрешениями, либо у меня есть права на чтение / запись, либо нет. Так как некоторая история сохранена, я, безусловно, делаю. Если в bash есть настройка, которая вызывает проблемы, когда этот файл не принадлежит пользователю, он либо будет жаловаться, либо вся функциональность истории не будет работать.
Тердон

когда вы выполняете historyкоманду, вывод, который вы видите, идентичен тому, что вы видите, работает cat .bash_history, кроме номеров строк? Я имею в виду historyсписок команд отметки времени или другую информацию? Причина, по которой я спрашиваю, состоит в том, что, если вы видите эти эзотерические вещи, это означает, что есть другой модуль / функция / программа, которая работает с историей оболочки, и неправильная или ошибочная версия чего бы то ни было, может причинить вам горе ,
MelBurslan

@Mel_Burslan да это то же самое, единственное отличие - номера строк.
Terdon

2
Ладно, довольно странное предложение, но это также излишняя проблема ;): попробуйте другой файл как HISTFILE, а не по умолчанию ~/.bash_history. Очень подробное объяснение: я предполагаю, что bash - это ваша оболочка по умолчанию, поэтому при запуске системы неинтерактивная оболочка является родителем вашей сессии X (я также предполагаю, что вы используете X), которая ничего не будет знать о параметре histappend (так как .bashrc только читать в интерактивных оболочках), так что до тех пор, пока эта родительская оболочка запускается, все в порядке, но после ее завершения (т.е. остановки системы) она будет переопределена ~/.bash_history(что по умолчанию) и испортит вашу историю ...
mpy

Ответы:


17

Проблема на самом деле сводится к разному поведению оболочек входа и не входа в систему. Я установил переменные, которые контролируют историю в моем ~/.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 только в файле, читаемом интерактивными оболочками, не входящими в систему, и, следовательно, каждый раз, когда я запускал оболочку другого типа, переменные игнорировались, а файл обрезался. соответственно.


Очень хорошая мысль, спасибо, что поделились! Однако я не согласен с: этот файл не читается при запуске оболочки входа в систему, он читается только интерактивными оболочками. Потому что оболочка входа также может быть интерактивной. Иначе весь механизм истории не будет иметь смысла. ИМХО .bashrcне читается (неинтерактивные ИЛИ логин оболочки).
mpy

@mpy Действительно, извините, я имел в виду интерактивные, не входящие в систему оболочки. Ответ отредактирован.
Тердон

1
@terdon, общая идиома в том, что параметры интерактивной оболочки не входят в ~ / .profile или ~ / .bash_profile. Параметры интерактивной оболочки помещаются в ~ / .bashrc. Чтобы избежать необходимости сохранять настройки в двух местах, следующие команды могут быть помещены вверху ~ / .bash_profile: export BASH_ENV=~/.bashrc ; if [ -f ~/.bashrc ]; then . ~/.bashrc; fi... и вверху ~ / .bashrc поставьте галочку, чтобы убедиться, что вы действительно работаете в интерактивном режиме: [ -z "$PS1" ] && return... Конечно, это просто идиома.
Ноа Спурриер

1
@NoahSpurrier BASH_ENVне имеет значения, он влияет только на неинтерактивные оболочки. Что касается «идиомы», то это то, что Debian начал и с которым я лично не согласен. У меня часто есть графические опции ( xsetи тому подобное) в моем .bashrc, и я не хочу, чтобы они были активными, когда я запускаю оболочки входа в систему из tty или через ssh. Я хочу, чтобы мои .profile и .bashrc разделились. Многие (хотя и не все) менеджеры входа в систему получают источник .profile, когда вы входите в систему, поэтому глобальные переменные лучше всего устанавливать там, где они будут считываться только один раз, а не каждый раз, когда вы открываете терминал.
Terdon

1
@WilsonF да. Файлы читаются последовательно, а личные файлы ( ~/.profileили ~/.bashrc) читаются последними. Все, что установлено в них, будет иметь приоритет над глобальными настройками. Вы совершенно правы, вы не должны устанавливать эти переменные в /etc/bash.bashrc. Используйте ~/.profile(или ~/.bash_profile) вместо этого.
Тердон

11

Я предлагаю использовать другой файл как 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
Явная настройка параметров истории по моему ~/.bash_profileрешила проблему. Я сейчас использую в ~/.bash_historyкачестве файла истории, но просто добавил все строки из ~/.bashrcпоказанного в моем вопросе ~/.bash_profile. Все еще не уверен, кто испортил интерактивные оболочки, но это, кажется, работает теперь, спасибо!
Terdon

1
Извините за отказ принять, но я забыл опубликовать ответ, объясняющий, что происходит. Я понял это с помощью @Gilles некоторое время назад и, наконец, решил опубликовать ответ. Я хотел принять мой, потому что он действительно объясняет проблему, а не предлагает (очень хороший) обходной путь и может помочь будущим посетителям.
Тердон

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, сразу после чего ловушка будет выполнена.

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

сигналы


Я не совсем понимаю, что вы делаете на этом скриншоте. Что /tmp/psoты убиваешь? Я понимаю вашу точку зрения о различных сигналах убийства (хотя, как вы говорите, я подумал, что это то, с чем history -aнужно иметь дело). Я проверю это некоторое время и сообщу.
Тердон

$ cat tmp / ps * \ n ps -o pid = | head -n1> ~ / tmp / pso \ n 17201 \ n
Ярослав Рахматуллин

0

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

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


Спасибо, но grep -r HIST /etc/profile.d/ничего не возвращает, а я уже проверил /etc/profile.
Terdon
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.