Обновление истории bash на других терминалах при выходе из одного терминала

15

Я знаю, что этот вопрос не является неясным, так как он задается здесь, обновлятьдублировать здесь).

То, что я пытаюсь достичь, немного другое. Мне не нравится идея моей подсказки переписывать файл каждый раз, когда lsя печатаю ( history -a; history -c; history -r).

Я хотел бы обновить файл при выходе. Это легко (на самом деле, по умолчанию), но вам нужно добавить вместо переписывания:

shopt -s histappend

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

Я предпочитаю делать это без проверки через $PS1все, commandчто я печатаю. Я думаю, что было бы лучше захватить какой-то сигнал. Как бы Вы это сделали? Если не возможно, может быть, просто cronjob?

Как мы можем решить эту загадку?

Доктор Беко
источник
1
Обратите внимание, что zsh делает это из коробки (и имеет много опций для тонкой настройки обмена историями).
Жиль "ТАК - перестань быть злым"
Спасибо @ Жиль; Забавно, годы я использую Linux, и я никогда не пробовал ничего, кроме bash. Может быть, пришло время проверить что-то новое, просто для удовольствия.
Доктор Беко

Ответы:

15

Вы говорите креативно и привлекательно? OK:

trap on_exit EXIT
trap on_usr1 USR1

on_exit() {
    history -a
    trap '' USR1
    killall -u "$USER" -USR1 bash
}

on_usr1() {
    history -n
}

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


Как это работает?

trapустанавливает обработчик сигнала для системного сигнала или одного из внутренних событий Bash. EXITСобытие любое контролируемое прекращение оболочки, в то время как USR1это SIGUSR1, бессмысленный сигнал мы присваивая.

Всякий раз, когда оболочка выходит, мы:

  • Добавить всю историю в файл явно.
  • Отключите SIGUSR1обработчик и заставьте эту оболочку игнорировать сигнал.
  • Отправьте сигнал всем запущенным bashпроцессам от одного и того же пользователя.

Когда SIGUSR1прибывает, мы:

  • Загрузите все новые записи из файла истории в список истории оболочки в памяти.

Из-за способом Баша ручки сигналов, не будет на самом деле получить новые данные истории , пока вы не попали Enterв следующий раз, так что это не делает лучше на этом фронте , чем положить history -nв PROMPT_COMMAND. Тем не менее, он сохраняет чтение файла постоянно, когда ничего не происходит, и запись вообще не происходит, пока оболочка не выйдет.


Однако здесь есть еще пара вопросов. Во-первых, ответом по умолчанию SIGUSR1является завершение оболочки. Любые другие bashпроцессы (например, запуск сценариев оболочки) будут уничтожены. .bashrcне загружается неинтерактивными оболочками. Вместо этого загружается файл с именемBASH_ENV : вы можете установить эту переменную в вашей среде глобально, чтобы указывать на файл с помощью:

trap '' USR1

в нем игнорировать сигнал в них (что решает проблему).

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

Майкл Гомер
источник
Интересно, если вы включили отметку времени в .bashrcфайле, а затем появилось что-то вроде cronjob и периодически прибегали к файлу, посылая SIGUSR1фрагмент кода, можете ли вы восстановить хронологическую историю со стрелками вверх?
Forquare
Это отличное решение, но на самом деле другие процессы завершаются после USR1. Такое поведение также происходит с USR2?
Доктор Беко
Я добавлю второй комментарий, потому что я удивлен. Почему процесс связывает TERM с USR1? Разве USR1 не должен использоваться только пользователем? Это какой-то linux bug?? Почему другие процессы ловят USR1? (Я знаю, что это не должно обсуждаться здесь, но, может быть, я расскажу об этом в правильном месте)
д-р Беко
Поведение по умолчанию почти всех сигналов - прекращение; это указано в POSIX . Это не ошибка. Bash позволит вам указать, что сигнал будет игнорироваться для всех его процессов, так что это хорошо для наших целей.
Майкл Гомер,
Спасибо @MichaelHomer. Эта спецификация, которую вы имели в виду, выполнена, BASH_ENVкак указано в этом ответе? Или вы знаете более стандартный способ выключить это зло?
Доктор Беко