Сохранять историю bash в нескольких терминальных окнах

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

Мне нужна история, которая:

  • Помнит все из каждого терминала
  • Доступно мгновенно из каждого терминала (например, если I ls), переключитесь на другой уже запущенный терминал и затем нажмите вверх, появится ls)
  • Не забывайте команду, если есть пробелы в начале команды.

Все, что я могу сделать, чтобы сделать bash более похожим на это?

452 голоса | спросил Oli 26 PM00000050000005631 2010, 17:04:56

20 ответов


278

Добавьте следующее в ~ /.bashrc

# Avoid duplicates
export HISTCONTROL=ignoredups:erasedups  
# When the shell exits, append to the history file instead of overwriting it
shopt -s histappend

# After each command, append to the history file and reread it
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"
ответил Pablo R. 26 PM00000060000004931 2010, 18:37:49
221

Итак, это вся моя связанная с историей .bashrc вещь:

export HISTCONTROL=ignoredups:erasedups  # no duplicate entries
export HISTSIZE=100000                   # big big history
export HISTFILESIZE=100000               # big big history
shopt -s histappend                      # append to history, don't overwrite it

# Save and reload the history after each command finishes
export PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

Протестировано с bash 3.2.17 в Mac OS X 10.5, bash 4.1.7 на 10.6.

ответил kch 19 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 19 Sep 2008 21:49:41 +0400 2008, 21:49:41
100

Вот моя попытка совместного использования истории сеансов Bash. Это позволит обмен историями между сессиями bash таким образом, чтобы счетчик истории не смешивался, а расширение истории, например !number, будет работать (с некоторыми ограничениями).

Использование Bash версии 4.1.5 в Ubuntu 10.04 LTS (Lucid Lynx).

HISTSIZE=9000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups

_bash_history_sync() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
  builtin history -c         #3
  builtin history -r         #4
}

history() {                  #5
  _bash_history_sync
  builtin history "[email protected]"
}

PROMPT_COMMAND=_bash_history_sync

Объяснение:

  1. Добавить только что введенную строку в $HISTFILE (по умолчанию - .bash_history). Это приведет к тому, что $HISTFILE будет расти на одну строку.

  2. Установка специальной переменной $HISTFILESIZE для некоторого значения приведет к тому, что Bash обрезает $HISTFILE не более $HISTFILESIZE строк, удалив самые старые записи.

  3. Очистите историю выполняемого сеанса. Это уменьшит счетчик истории на количество $HISTSIZE.

  4. Прочитайте содержимое $HISTFILE и вставьте их в текущую текущую историю сеансов. это увеличит счетчик истории на количество строк в $HISTFILE. Обратите внимание, что количество строк $HISTFILE не обязательно $HISTFILESIZE.

  5. Функция history() переопределяет встроенную историю, чтобы убедиться, что история синхронизирована до ее отображения. Это необходимо для расширения истории по номеру (подробнее об этом позже).

Дополнительные пояснения:

  • Шаг 1 гарантирует, что команда из текущего текущего сеанса будет записана в глобальный файл истории.

  • Шаг 4 гарантирует, что команды из других сеансов будут прочитаны в текущей истории сеанса.

  • Поскольку шаг 4 поднимет счетчик истории, нам нужно каким-то образом уменьшить счетчик. Это делается на шаге 3.

  • На шаге 3 счетчик истории уменьшается на $HISTSIZE. На шаге 4 счетчик истории увеличивается числом строк в $HISTFILE. На шаге 2 мы убеждаемся, что количество строк $HISTFILE равно точно $HISTSIZE (это означает, что $HISTFILESIZE должен быть таким же, как $ HISTSIZE).

Об ограничениях расширения истории:

При использовании расширения истории по номеру, вы должны всегда находить число сразу перед его использованием. Это означает, что нет подсказки подсказки bash между просмотром номера и использованием его. Обычно это означает, что нет ввода и нет ctrl + c.

Как правило, после того, как у вас есть более одного сеанса Bash, нет никакой гарантии, что расширение истории по числу будет сохранять свое значение между двумя отображаемыми подсказками Bash. Потому что, когда выполняется $HISTSIZE, история из всех других сессий Bash интегрируется в историю текущего сеанса. Если какой-либо другой сеанс bash имеет новую команду, тогда номера истории текущего сеанса будут разными.

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

Обычно я использую расширение истории по числу, подобному этому

PROMPT_COMMAND

Я рекомендую использовать следующие параметры Bash.

$ history | grep something #note number
$ !number

Странные ошибки:

Запуск команды history, переданной на все, приведет к тому, что команда будет дважды указана в истории. Например:

## reedit a history substitution line if it failed
shopt -s histreedit
## edit a recalled history line before executing
shopt -s histverify

Все будут перечислены в истории дважды. Я понятия не имею, почему.

Идеи для улучшений:

  • Измените функцию $ history | head $ history | tail $ history | grep foo $ history | true $ history | false , чтобы она не выполнялась каждый раз. Например, он не должен выполняться после _bash_history_sync() в приглашении. Я часто использую CTRL+C, чтобы отбросить длинную командную строку, когда я решаю, что я не хочу выполнять эту строку. Иногда мне нужно использовать CTRL+C, чтобы остановить скрипт завершения Bash.

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

ответил lesmana 16 J0000006Europe/Moscow 2010, 20:11:47
37

Я не знаю, как использовать bash. Но это одна из самых популярных функций zsh .
Лично я предпочитаю zsh over bash, поэтому рекомендую попробовать его.

Вот часть моего .zshrc, который имеет дело с историей:

SAVEHIST=10000 # Number of entries
HISTSIZE=10000
HISTFILE=~/.zsh/history # File
setopt APPEND_HISTORY # Don't erase history
setopt EXTENDED_HISTORY # Add additional data to history like timestamp
setopt INC_APPEND_HISTORY # Add immediately
setopt HIST_FIND_NO_DUPS # Don't show duplicates in search
setopt HIST_IGNORE_SPACE # Don't preserve spaces. You may want to turn it off
setopt NO_HIST_BEEP # Don't beep
setopt SHARE_HISTORY # Share history between session/terminals
ответил Maciej Piechotka 26 PM00000050000003331 2010, 17:20:33
14

Для этого вам нужно добавить две строки в ваш ~/.bashrc:

shopt -s histappend
PROMPT_COMMAND="history -a;history -c;history -r;$PROMPT_COMMAND"

Из man bash:

  

Если включена опция оболочки histappend (см. описание магазина в разделе SHELL BUILTIN COMMANDS ниже), строки добавляются в файл истории, в противном случае файл истории переписан.

ответил Chris Down 25 52011vEurope/Moscow11bEurope/MoscowFri, 25 Nov 2011 19:46:04 +0400 2011, 19:46:04
9

Вы можете отредактировать свое приглашение BASH для запуска «истории -a» и «истории -r», предложенной Мурером:

savePS1=$PS1

(в случае, если вам что-то не хватает, что почти гарантировано)

PS1=$savePS1`history -a;history -r`

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

После того, как ваша переменная PS1 настроена так, как вы хотите, установите ее навсегда в файле ~ /.bashrc.

Если вы хотите вернуться к исходному приглашению во время тестирования, выполните следующие действия:

PS1=$savePS1

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

ответил Schof 19 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 19 Sep 2008 23:38:22 +0400 2008, 23:38:22
8

Если вам требуется синхронизирующее решение истории bash или zsh, которое также решает проблему ниже, а затем посмотрите на http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-shell.html

Проблема заключается в следующем: у меня есть два окна оболочки A и B. В окне оболочки A я запускаю sleep 9999 и (не дожидаясь завершения сна) в окне оболочки B, Я хочу видеть sleep 9999 в истории bash.

Причина, по которой большинство других решений здесь не решает эту проблему, заключается в том, что они записывают свои исторические изменения в файл истории, используя PROMPT_COMMAND или PS1, оба которые выполняются слишком поздно, только после завершения команды sleep 9999.

ответил pts 25 MarpmFri, 25 Mar 2011 20:40:35 +03002011-03-25T20:40:35+03:0008 2011, 20:40:35
6

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

ответил jtimberman 19 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 19 Sep 2008 21:38:26 +0400 2008, 21:38:26
6

Вот альтернатива, которую я использую. Это громоздко, но в нем рассматривается проблема, о которой @axel_c упоминает, где иногда вам может понадобиться отдельный экземпляр истории в каждом терминале (один для make, один для мониторинга, один для vim и т. Д.).

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

history | grep -v history >> ~/master_history.txt

Это добавляет всю историю из текущего терминала в файл с именем master_history.txt в вашем домашнем каталоге.

У меня также есть отдельная горячая клавиша для поиска по основному файлу истории:

cat /home/toby/master_history.txt | grep -i

Я использую cat | grep, потому что он оставляет курсор в конце, чтобы ввести мое регулярное выражение. Менее уродливым способом сделать это было бы добавить несколько сценариев на ваш путь для выполнения этих задач, но горячие клавиши работают для моих целей. Я также периодически вытягиваю историю с других хостов, над которыми я работал, и добавляю эту историю в свой файл master_history.txt.

Всегда приятно быстро находить и находить это сложное регулярное выражение, которое вы использовали, или этот странный perl one-liner, который вы создали 7 месяцев назад.

ответил Toby 20 42014vEurope/Moscow11bEurope/MoscowThu, 20 Nov 2014 17:53:01 +0300 2014, 17:53:01
5

Я могу предложить исправление для последнего: убедитесь, что переменная env HISTCONTROL не указывает «ignorespace» (или «ignoreboth»).

Но я чувствую вашу боль с несколькими параллельными сеансами. Это просто плохо обрабатывается в bash.

ответил jmanning2k 26 PM00000050000005831 2010, 17:59:58
4

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

# Write history after each command
_bash_history_append() {
    builtin history -a
}
PROMPT_COMMAND="_bash_history_append; $PROMPT_COMMAND"

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

make
ls -lh target/*.foo
scp target/artifact.foo vm:~/

(упрощенный пример)

И в другом:

pv ~/test.data | nc vm:5000 >> output
less output
mv output output.backup1

Никоим образом я не хочу, чтобы команда была разделяемой

ответил Yarek T 23 J000000Thursday15 2015, 12:05:30
3

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

Если вы явно вводите «историю», ИЛИ, если вы открываете новое окно, вы получаете историю из всех предыдущих окон.

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

# Consistent and forever bash history
HISTSIZE=100000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups

_bash_history_sync() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
}

_bash_history_sync_and_reload() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
  builtin history -c         #3
  builtin history -r         #4
}

history() {                  #5
  _bash_history_sync_and_reload
  builtin history "[email protected]"
}

export HISTTIMEFORMAT="%y/%m/%d %H:%M:%S   "
PROMPT_COMMAND='history 1 >> ${HOME}/.bash_eternal_history'
PROMPT_COMMAND=_bash_history_sync;$PROMPT_COMMAND
ответил rouble 15 PMpSat, 15 Apr 2017 20:43:18 +030043Saturday 2017, 20:43:18
1

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

        # write existing history to the old file
        history -a

        # set new historyfile
        export HISTFILE="$1"
        export HISET=$1

        # touch the new file to make sure it exists
        touch $HISTFILE
        # load new history file
        history -r $HISTFILE

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

Полный источник: https://github.com/simotek/scripts -config /blob /master /hiset.sh

ответил simotek 1 J0000006Europe/Moscow 2014, 10:02:03
1

Я решил поместить историю в файл-за-tty, так как несколько человек могут работать на одном сервере - разделение команд каждого сеанса упрощает аудит.

# Convert /dev/nnn/X or /dev/nnnX to "nnnX"
HISTSUFFIX=`tty | sed 's/\///g;s/^dev//g'`
# History file is now .bash_history_pts0
HISTFILE=".bash_history_$HISTSUFFIX"
HISTTIMEFORMAT="%y-%m-%d %H:%M:%S "
HISTCONTROL=ignoredups:ignorespace
shopt -s histappend
HISTSIZE=1000
HISTFILESIZE=5000

История теперь выглядит так:

[email protected]:~# test 123
[email protected]:~# test 5451
[email protected]:~# history
1  15-08-11 10:09:58 test 123
2  15-08-11 10:10:00 test 5451
3  15-08-11 10:10:02 history

С похожими файлами:

[email protected]:~# ls -la .bash*
-rw------- 1 root root  4275 Aug 11 09:42 .bash_history_pts0
-rw------- 1 root root    75 Aug 11 09:49 .bash_history_pts1
-rw-r--r-- 1 root root  3120 Aug 11 10:09 .bashrc
ответил Litch 11 AM00000030000002131 2015, 03:15:21
1

Здесь я укажу одну проблему с

export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"

и

PROMPT_COMMAND="$PROMPT_COMMAND;history -a; history -n"

Если вы запускаете source ~ /.bashrc, $ PROMPT_COMMAND будет выглядеть как

"history -a; history -c; history -r history -a; history -c; history -r"

и

"history -a; history -n history -a; history -n"

Это повторение происходит каждый раз при запуске 'source ~ /.bashrc'. Вы можете проверить PROMPT_COMMAND после каждого запуска «source ~ /.bashrc», запустив «echo $ PROMPT_COMMAND».

Вы могли видеть, что некоторые команды, по-видимому, нарушены: «history -n history -a». Но хорошая новость заключается в том, что он по-прежнему работает, потому что другие части по-прежнему образуют правильную последовательность команд (просто с привлечением некоторых дополнительных затрат из-за повторного выполнения некоторых команд. И не так чисто.)

Лично я использую следующую простую версию:

shopt -s histappend
PROMPT_COMMAND="history -a; history -c; history -r"

, который имеет большинство функций, но не имеет такой проблемы, как указано выше.

Еще один момент: нет ничего волшебного . PROMPT_COMMAND - это просто переменная среды bash. Команды в нем выполняются до того, как вы получите приглашение bash (знак $). Например, ваш PROMPT_COMMAND является «echo 123», и вы запускаете «ls» в своем терминале. Эффект подобен запуску «ls; echo 123».

$ PROMPT_COMMAND="echo 123"

output (Так же, как запуск: PROMPT_COMMAND = "echo 123"; $ PROMPT_COMMAND '):

123

Выполните следующее:

$ echo 3

вывод:

3
123

«history -a» используется для записи команд истории в памяти в ~ /.bash_history

«history -c» используется для очистки команд истории в памяти

«history -r» используется для чтения команд истории из ~ /.bash_history в память

См. объяснение команды истории здесь: http://ss64.com/bash/history.html

PS: Как отмечали другие пользователи, экспорт не нужен. См. использование экспорта в .bashrc

ответил fstang 10 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 10 Sep 2016 22:30:27 +0300 2016, 22:30:27
0

Вот фрагмент из моего .bashrc и кратких объяснений там, где это необходимо:

# The following line ensures that history logs screen commands as well
shopt -s histappend

# This line makes the history file to be rewritten and reread at each bash prompt
PROMPT_COMMAND="$PROMPT_COMMAND;history -a; history -n"
# Have lots of history
HISTSIZE=100000         # remember the last 100000 commands
HISTFILESIZE=100000     # start truncating commands after 100000 lines
HISTCONTROL=ignoreboth  # ignoreboth is shorthand for ignorespace and     ignoredups

HISTFILESIZE и HISTSIZE являются личными предпочтениями, и вы можете изменить их в соответствии с вашими вкусами.

ответил Hopping Bunny 13 Mayam15 2015, 07:48:07
0

Это работает для ZSH

##############################################################################
# History Configuration for ZSH
##############################################################################
HISTSIZE=10000               #How many lines of history to keep in memory
HISTFILE=~/.zsh_history     #Where to save history to disk
SAVEHIST=10000               #Number of history entries to save to disk
#HISTDUP=erase               #Erase duplicates in the history file
setopt    appendhistory     #Append history to the history file (no overwriting)
setopt    sharehistory      #Share history across terminals
setopt    incappendhistory  #Immediately append to the history file, not just when a term is killed
ответил Mulki 24 J000000Monday17 2017, 23:49:12
0

Я давно хотел этого, особенно возможность получить команду, где она была запущена для повторного выполнения в новом проекте (или найти каталог по команде). Поэтому я добавил этот инструмент вместе с предыдущими решениями для хранения глобальной истории CLI с помощью интерактивного инструмента grepping называемый перколом (отображается на C ^ R). Это все еще пятно на первой машине, которую я начал использовать, теперь с историей CLI 2 года.

Это не связано с локальной историей CLI в отношении клавиш со стрелками, но позволяет вам легко получить доступ к глобальной истории (что также можно сопоставить с чем-то другим, кроме C ^ R)

ответил Gordon Wells 18 AM00000010000002231 2017, 01:31:22
0

Вот решение, в котором не смешивает истории с отдельных сеансов!

В основном нужно хранить историю каждой сессии отдельно и воссоздавать ее в каждом приглашении. Да, он использует больше ресурсов, но это не так медленно, как может показаться - задержка начинает заметна, только если у вас более 100000 записей истории.

Вот основная логика:

# on every prompt, save new history to dedicated file and recreate full history
# by reading all files, always keeping history from current session on top.
update_history () {
  history -a ${HISTFILE}.$$
  history -c
  history -r
  for f in `ls ${HISTFILE}.[0-9]* | grep -v "${HISTFILE}.$$\$"`; do
    history -r $f
  done
  history -r "${HISTFILE}.$$"
}
export PROMPT_COMMAND='update_history'

# merge session history into main history file on bash exit
merge_session_history () {
  cat ${HISTFILE}.$$ >> $HISTFILE
  rm ${HISTFILE}.$$
}
trap merge_session_history EXIT

См. этот метод для полного решения, включая некоторые меры предосторожности и оптимизацию производительности.

ответил Jan Warchoł 14 MarpmWed, 14 Mar 2018 12:09:24 +03002018-03-14T12:09:24+03:0012 2018, 12:09:24
0

Потому что я предпочитаю бесконечную историю, которая сохраняется в пользовательском файле. Я создаю эту конфигурацию на основе https://stackoverflow.com/a/19533853/4632019 :

export HISTFILESIZE=
export HISTSIZE=
export HISTTIMEFORMAT="[%F %T] "

export HISTFILE=~/.bash_myhistory
PROMPT_COMMAND="history -a; history -r; $PROMPT_COMMAND"
ответил Eugen Konkov 25 Maypm18 2018, 16:50:53

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132