web-dev-qa-db-ja.com

複数のターミナルウィンドウでbash履歴を保持する

常に複数のターミナルを開いています。 2から10のどこでも、さまざまな小技やボブを行います。ここで、別の端末セットを再起動して開いたとします。特定のことを覚えている人もいれば、忘れている人もいます。

次のような履歴が必要です。

  • すべての端末からすべてを覚えています
  • すべての端末から即座にアクセスできます(たとえば、1つの端末でlsを実行している場合は、既に実行中の別の端末に切り替えてから上に押すと、lsが表示されます)
  • コマンドの前にスペースがある場合は、コマンドを忘れないでください。

もっとbashをそのように機能させるために私ができることは何ですか?

565
Oli

以下を〜/ .bashrcに追加します

# Avoid duplicates
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
Prompt_COMMAND="${Prompt_COMMAND:+$Prompt_COMMAND$'\n'}history -a; history -c; history -r"
355
Pablo R.

だから、これは私の歴史に関連するすべてです.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"

Mac OS X 10.5ではbash 3.2.17、10.6ではbash 4.1.7でテスト済み。

257
kch

これが、Bashセッションの履歴共有における私の試みです。これにより、bashセッション間の履歴共有が有効になり、履歴カウンターが混同されず、_!number_のような履歴拡張が機能します(いくつかの制約あり)。

Ubuntu 10.04 LTS(Lucid Lynx)でBashバージョン4.1.5を使用する。

_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 "$@"
}

Prompt_COMMAND=_bash_history_sync
_

説明:

  1. 入力した行を_$HISTFILE_に追加します(デフォルトは_.bash_history_です)。これにより、_$HISTFILE_が1行大きくなります。

  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_と同じでなければなりません)。

履歴拡張の制約について:

番号による履歴拡張を使用する場合、使用する前にalways番号を調べるimmediatelyする必要があります。つまり、番号の検索と使用の間にbashプロンプトが表示されないということです。通常は、EnterキーもCtrl + Cキーもありません。

通常、Bashセッションが複数ある場合、2つのBashプロンプト表示の間で、数値による履歴拡張がその値を保持するという保証はありません。 _Prompt_COMMAND_が実行されると、他のすべてのBashセッションの履歴が現在のセッションの履歴に統合されるためです。他のbashセッションに新しいコマンドがある場合、現在のセッションの履歴番号は異なります。

この制約は妥当だと思います。とにかく私は任意の履歴番号を思い出せないのでとにかく毎回番号を調べなければなりません。

通常はこのように番号による履歴展開を使います

_$ history | grep something #note number
$ !number
_

以下のBashオプションの使用をお勧めします。

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

奇妙なバグ:

何かにパイプされた履歴コマンドを実行すると、そのコマンドは履歴に2回リストされます。例えば:

_$ history | head
$ history | tail
$ history | grep foo
$ history | true
$ history | false
_

すべてが2回履歴にリストされます。なぜか分かりません。

改善のためのアイデア:

  • 関数_bash_history_sync()を変更して、毎回実行されないようにします。たとえば、プロンプトで_CTRL+C_の後に実行しないでください。長いコマンドラインを実行しない場合は、_CTRL+C_を使用して長いコマンドラインを破棄することがよくあります。場合によっては、Bash完了スクリプトを停止するために_CTRL+C_を使用する必要があります。

  • 現在のセッションからのコマンドは、常に現在のセッションの履歴の中で最新のものでなければなりません。これには、特定の履歴番号がこのセッションの履歴エントリの値を保持するという副作用もあります。

123
lesmana

bashの使い方を知りません。しかし、これは zsh の最も人気のある機能の1つです。
個人的にはzshよりも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
45

これを行うには、~/.bashrcに2行追加する必要があります。

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

man bashから:

Histappendシェルオプションが有効になっている場合(以下のシェルの組み込みコマンドの下のshoptの説明を参照)、行が履歴ファイルに追加されます。そうでない場合、履歴ファイルは上書きされます。

17
Chris Down

Muerrが提案した「history -a」と「history -r」を実行するようにBASHプロンプトを編集できます。

savePS1=$PS1

(あなたが何かを台無しにした場合、それはほぼ保証されています)

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

(これらはバックティックであることに注意してください。これらはすべてのプロンプトでhistory -aおよびhistory -rを実行します。テキストを出力しないため、プロンプトは変更されません。

PS1変数を希望どおりに設定したら、〜/ .bashrcファイルに永続的に設定します。

テスト中に元のプロンプトに戻りたい場合は、次のようにします。

PS1=$savePS1

これについては基本的なテストを行って、動作することを確認しましたが、すべてのプロンプトでhistory -a;history -rを実行した場合の副作用については説明できません。

11
Schof

以下の問題も解決するbashまたはzsh履歴同期ソリューションが必要な場合は、 http://ptspts.blogspot.com/2011/03/how-to-automatically-synchronize-Shell.html)で参照してください。

問題は次のとおりです。2つのシェルウィンドウAとBがあります。シェルウィンドウAでsleep 9999を実行し、シェルウィンドウBで(スリープが終了するのを待たずに)表示したいbash履歴のsleep 9999

ここで他のほとんどのソリューションがこの問題を解決しない理由は、Prompt_COMMANDまたはPS1を使用して履歴変更を履歴ファイルに書き込んでいるためです。 sleep 9999コマンドが終了しました。

10
pts

そうです、最後にこれはまともな解決策を見つけるのに私を悩ませました:

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

これが行うことは、このスレッドで言われたことの一種の融合ですが、すべてのコマンドの後にグローバル履歴をリロードする理由がわかりません。他の端末で何が発生するかを気にすることはほとんどありませんが、常に1つの端末で一連のコマンドを実行します。

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

(簡略化した例)

そして別の:

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

コマンドを共有したくない

9
Yarek T

history -aを使用して現在のセッションの履歴をhistfileに追加し、他の端末でhistory -rを使用してhistfileを読み取ることができます。

9
jtimberman

ここに私が使用する代替案があります。面倒ですが、@ axel_cが言及した、各端末で個別の履歴インスタンスを作成したい場合がある問題(1つはmake、もう1つは監視、vimなど)に対処します。

常に更新する個別の履歴ファイルを保持しています。以下をホットキーにマッピングしました:

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

これにより、現在の端末からのすべての履歴がホームディレクトリのmaster_history.txtというファイルに追加されます。

マスター履歴ファイルを検索するための別のホットキーもあります。

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

猫を使う|カーソルを最後に置いて正規表現に入るので、grep。これを行うためのそれほど醜くない方法は、これらのタスクを実行するためにパスにいくつかのスクリプトを追加することですが、ホットキーは私の目的のために機能します。また、定期的に履歴を他のホストから取得し、その履歴をmaster_history.txtファイルに追加します。

使用したトリッキーな正規表現や、7か月前に思いついた奇妙なPerlワンライナーをすばやく検索して見つけることができるのは、いつも素晴らしいことです。

8
Toby

最後の修正を提供できます。環境変数HISTCONTROLで「ignorespace」(または「ignoreboth」)が指定されていないことを確認してください。

しかし、私は複数の同時セッションであなたの痛みを感じます。単にbashではうまく処理されません。

7
jmanning2k

@lesmanaの answer に対する私の拡張を以下に示します。主な違いは、並行ウィンドウは履歴を共有しないことです。これは、他のウィンドウからのコンテキストが現在のウィンドウに読み込まれなくても、ウィンドウで作業を続けることができることを意味します。

「履歴」を明示的に入力すると、OR新しいウィンドウを開くと、以前のすべてのウィンドウから履歴が取得されます。

また、 この戦略 を使用して、自分のマシンでこれまでに入力されたすべてのコマンドをアーカイブします。

# 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 "$@"
}

export HISTTIMEFORMAT="%y/%m/%d %H:%M:%S   "
Prompt_COMMAND='history 1 >> ${HOME}/.bash_eternal_history'
Prompt_COMMAND=_bash_history_sync;$Prompt_COMMAND
7
rouble

複数のユーザーが同じサーバーで作業している可能性があるため、私は履歴をfile-per-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

履歴は次のようになります。

user@Host:~# test 123
user@Host:~# test 5451
user@Host:~# 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

ファイルは次のようになります。

user@Host:~# 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
6
Litch

ここで私は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」を実行するたびに発生します。 'echo $ Prompt_COMMAND'を実行することで、 'source〜/ .bashrc'を実行するたびに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"

出力( '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:他のユーザーが指摘したように、exportは不要です。参照: 。bashrcでのエクスポートの使用

5
fstang

セッションまたはタスクごとに履歴ファイルを設定するためのスクリプトを作成しました。

        # 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

3
simotek

これは、個々のセッションの履歴をしない解決策です!

基本的に、各セッションの履歴を個別に保存し、すべてのプロンプトでそれを再作成する必要があります。はい、より多くのリソースを使用しますが、聞こえるほど遅くはありません-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

いくつかの保護手段とパフォーマンスの最適化を含む完全なソリューションについては、 この要点 を参照してください。

3
Jan Warchoł

カスタムファイルに保存した無限の履歴が好きだから。私はこの構成を 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"
2
Eugen Konkov

これは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
2
Mulki

私は長い間、特に新しいプロジェクトで再実行するために実行された場所でコマンドを取得する機能(またはコマンドでディレクトリを検索する機能)を望んでいました。したがって、私は this tool を組み合わせて、グローバルCLI履歴を保存するための以前のソリューションと、percol(C ^ Rにマップされる)と呼ばれるインタラクティブなgreppingツールを組み合わせます。それは私がそれを使い始めた最初のマシンではまだ滑らかで、2年以上前のCLI履歴があります。

矢印キーに関する限り、これはローカルCLI履歴を混乱させませんが、グローバル履歴に非常に簡単にアクセスできます(C ^ R以外のものにマップすることもできます)。

2
Gordon Wells

これが私の.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は個人的な設定であり、好みに応じて変更できます。

0
Hopping Bunny