web-dev-qa-db-ja.com

Bashの履歴:「無視された」と「消去された」の設定がセッション全体で共通の履歴と競合する

まず、これはSEの既存のスレッドの複製ではありません。私はより良いbash履歴でこれら2つのスレッド( 1st2nd )を読みましたが、どれも機能しません-ちなみに私はFedora 15を使用しています。

ユーザーディレクトリ(/ home/aahan /)の.bashrcファイルに以下を追加しましたが、機能しません。誰か手がかりはありますか?

HISTCONTROL=ignoredups:erasedups  # no duplicate entries
HISTSIZE=1000                     # custom history size
HISTFILESIZE=100000                 # custom history file size
shopt -s histappend                      # append to history, don't overwrite it
Prompt_COMMAND="history -a; history -c; history -r; $Prompt_COMMAND"  # Save and reload the history after each command finishes

わかりました、これはbashの履歴(優先度)に必要なものです。

  • 重複を保存せず、既存のものを消去する
  • 開いているすべての端末と履歴をすぐに共有する
  • 常に履歴を追加し、上書きしない
  • 複数行のコマンドを単一のコマンドとして保存する(デフォルトではオフ)
  • デフォルトの履歴サイズと履歴ファイルサイズは何ですか?
92
its_me

これは実際には非常に興味深い動作であり、私は最初に質問を非常に過小評価していたことを認めます。しかし、最初の事実:

1.機能するもの

機能はいくつかの方法で実現できますが、それぞれの動作は少し異なります。いずれの場合も、履歴を別の端末に「転送」(更新)するには、 Enter ターミナルで、履歴を取得したい場合。

  • オプション1:

    shopt -s histappend
    HISTCONTROL=ignoredups
    Prompt_COMMAND="history -a; history -n; $Prompt_COMMAND"
    

    これには2つの欠点があります。

    1. ログイン(端末を開く)時に、履歴ファイルの最後のコマンドが現在の端末の履歴バッファーに2回読み込まれます。
    2. 異なる端末のバッファは、履歴ファイルとの同期を維持しません。
  • オプション2:

    HISTCONTROL=ignoredups
    Prompt_COMMAND="history -a; history -c; history -r; $Prompt_COMMAND"
    

    (はい、shopt -s histappendは不要です。はいhistory -cの真ん中にある必要がありますPrompt_COMMAND )このバージョンには、2つの重要な欠点もあります。

    1. 履歴ファイルを初期化する必要があります。 少なくとも1つの空でない行を含める必要があります(何でもかまいません)。
    2. historyコマンドは誤った出力を出す可能性があります-以下を参照してください。

[編集] "そして勝者は..."

  • オプション3:

    HISTCONTROL=ignoredups:erasedups
    shopt -s histappend
    Prompt_COMMAND="history -n; history -w; history -c; history -r; $Prompt_COMMAND"
    

    これは可能な限りです。 erasedupsと共通の履歴の両方を同時に機能させるのはonlyオプションです。 これはおそらく、すべての問題の最終的な解決策です、アーハン。


2.オプション2が機能しないように見える理由(または:本当に )期待どおりに動作しません)?

すでに述べたように、上記のソリューションはそれぞれ異なる動作をします。しかし設定がどのように機能するかについて最も誤解を招く解釈は、historyコマンドの出力を分析することから得られます。多くの場合、コマンドはfalse出力を提供できます。どうして? それが実行されるのでbeforePrompt_COMMAND!に含まれる他のhistoryコマンドのシーケンスただし、2番目または3番目のオプションを使用する場合は、.bash_historyの内容の変更を監視して(たとえばwatch -n1 "tail -n20 .bash_history"を使用して)、実際の履歴を確認できます。

3.なぜオプション3がそれほど複雑なのですか?

それはすべてerasedupsの動作にあります。 bashマニュアルに記載されているように、 "(...)erasedupsを指定すると、現在の行と一致する以前のすべての行が、その行が保存される前に履歴リストから削除されます"。したがって、これは実際にOPが望んだものです(そして、以前考えたように、重複が表示されないようにするだけではありません順番にhistory -.コマンドのそれぞれがPrompt_COMMANDに含まれる必要がある、または含まれない理由は次のとおりです。

  • history -nhas他の端末から保存されたコマンドをhistory -wから読み取る.bash_historyの前にある、

  • history -whas履歴をファイルに保存し、重複を消去するためにそこにあります、

  • history -a必須ではありませんhistory -wの代わりに配置します。これは、重複の消去をトリガーしないためです。

  • history -c必要です。これは、各コマンドの後に履歴バッファが破棄されるのを防ぐためです。

  • そして最後に、history -r必要であり、ファイルから履歴バッファを復元し、最終的に履歴を端末セッション間で共有します。

126
rozcietrzewiacz

プロンプトコマンドでは、-cスイッチを使用しています。 man bashから:

-cすべてのエントリを削除して履歴リストをクリアします

開いているすべてのターミナルで履歴を共有するには、-nを使用できます。

-n履歴ファイルから現在の履歴リストにまだ読み込まれていない履歴行を読み取ります。これらは、現在のbashセッションの開始以降に履歴ファイルに追加された行です。

デフォルトのサイズもマニュアルにあります:

HISTSIZEコマンド履歴に記憶するコマンドの数(以下の履歴を参照)。デフォルト値は500です。

複数行のコマンドを保存するには:

cmdhist Shellオプションを有効にすると、シェルは複数行コマンドの各行を同じ履歴エントリに保存しようとし、構文の正確さを保つために必要に応じてセミコロンを追加します。 lithist Shellオプションを使用すると、シェルはコマンドをセミコロンの代わりに改行を埋め込んで保存します。

また、HIST *コマンドの前にexportを付けないでください。これらは環境変数ではなくbash専用の変数です。HISTCONTROL=ignoredups:erasedupsで十分です。

8
jasonwryan

これが私が思いついたもので、今のところ満足しています…

alias hfix='history -n && history | sort -k2 -k1nr | uniq -f1 | sort -n | cut -c8- > ~/.tmp$$ && history -c && history -r ~/.tmp$$ && history -w && rm ~/.tmp$$'  
HISTCONTROL=ignorespace  
shopt -s histappend  
shopt -s extglob  
HISTSIZE=1000  
HISTFILESIZE=2000  
export HISTIGNORE="!(+(*\ *))"  
Prompt_COMMAND="hfix; $Prompt_COMMAND" 

ノート:

  • はい、それは複雑です...しかし、それはすべての重複を削除し、それでも各ターミナル内で年表を保持します!
  • 私のHISTIGNOREは、引数を持たないすべてのコマンドを無視します。これは、一部の人々にとって望ましくない場合があり、除外することができます。
8
user41176

代わりにこれを使用してください:

HISTCONTROL=ignoreboth
1
verndog

次のことを忘れているため、機能しません。

 -n   read all history lines not already read from the history file
      and append them to the history list

ただし、history -nが有効な場合、export HISTCONTROL=ignoreboth:erasedupsはバグがあるようです。

実験してみましょう:

$ Prompt_COMMAND=
$ export HISTCONTROL=ignoreboth:erasedups
$ export HISTFILE=~/.bash_myhistory
$ HISTIGNORE='history:history -w'
$ history -c
$ history -w

ここでは、dupsの消去をオンにし、履歴をカスタムファイルに切り替え、履歴をクリアします。すべてのコマンドが完了すると、空の履歴ファイルと現在の履歴に1つのコマンドがあります。

$ history
$ cat ~/.bash_myhistory
$ history
$ 1  [2019-06-17 14:57:19] cat ~/.bash_myhistory

2番目のターミナルを開き、これらの6つのコマンドも実行します。その後:

$ echo "X"
$ echo "Y"
$ history -w
$ history
  1  [2019-06-17 15:00:21] echo "X"
  2  [2019-06-17 15:00:23] echo "Y"

現在の履歴には2つのコマンドがあり、履歴ファイルには次のものが含まれています。

#1560772821
echo "X"
#1560772823
echo "Y"

最初のターミナルに戻る:

$ history -n
$ history
1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
2  [2019-06-17 15:03:12] history -n

ええと... echoコマンドはどれも読み込まれません。もう一度2番目の端末に切り替えて、

$ echo "Z"
$ history -w

履歴ファイルは次のとおりです。

#1560772821
echo "X"
#1560772823
echo "Y"
#1560773057
echo "Z"

もう一度最初の端末に切り替えます。

$ history -n
$ history
  1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
  2  [2019-06-17 15:03:12] history -n
echo "Z"

echo "Z"コマンドがhistory -nにマージされていることがわかります。

別のバグは、コマンドがコマンド時間ではなくコマンド番号で履歴から読み取られるためだと思います。他のechoコマンドが履歴に表示されることを期待しています

0
Eugen Konkov

私はここに答えを組み合わせて行きました:

  • 最後に履歴をマージしたいので、トラップ機能を使いました。
  • ホストで区切られた履歴ファイルも必要なので、ホスト名に応じてディレクトリと名前付きファイルを指すようにHISTFILEを変更しました。
  • クリアテキストのパスワードを入力して履歴に表示しないように、ignorespaceオプションを追加しました。例:$ ./.secretfunction -user myuser -password mypasswordはスペースで始まるため、保存されません。
  • history*exitをHISTIGNOREに追加したのは、history | grep awesomecommandなどの過去の履歴を含むコマンドを通常は必要としないためです。 logout、fg、bgなどのような他のものを追加できます。
  • それをすべて〜/ .bash_aliasesファイルに入れて、アップグレード時に競合することがないようにしています。
HISTCONTROL=ignoreboth:erasedups:ignorespace
HISTIGNORE="history*:exit"
HISTFILE=~/.bash_history/.$(hostname)_history
shopt -s histappend
function historymerge {
    history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
Prompt_COMMAND="history -a; $Prompt_COMMAND"

〜/をGrepしてPrompt_COMMANDを実行し、history -aですでに変更されていないことを確認します。 TIME/DATE形式HISTTIMEFORMAT="%x %r %Z "も追加しましたが、ロケールに依存するため、上記のブロックには含めませんでした。

0
Marlon

erasedupsは、先頭と末尾のスペースを切り捨てません(一部の言語ではchompのように)。これはバグです。また、erasedupsは以前のすべてのエントリを削除しません。

0

@rozcietrzewiaczのオプション3と終了トラップを組み合わせて使用​​すると、端末は、終了時に収束する独自の独立した履歴セッションを維持できます。リモートのホームディレクトリを共有する異なるマシン間での複数のセッションでもうまく機能するようです。

export HISTSIZE=5000
export HISTFILESIZE=5000
export HISTCONTROL=ignorespace:erasedups
shopt -s histappend
function historymerge {
    history -n; history -w; history -c; history -r;
}
trap historymerge EXIT
Prompt_COMMAND="history -a; $Prompt_COMMAND"
  • historymerge関数は、履歴ファイルからセッション外の行をロードし、それらをセッション履歴と結合し、重複除去を使用して新しい履歴ファイルを書き出し(これにより、以前に追加された重複行をつぶす)、履歴を再ロードします。

  • history -aプロンプトでは、すべてのコマンドで重複排除を行わずに履歴ファイルを更新するため、履歴が失われる可能性を最小限に抑えます。

  • 最後に、トラップはセッションを閉じるときにhistorymergeをトリガーし、最新のクリーンな履歴ファイルを探します。最近閉じたセッションのコマンドは、ファイルの最後にバブリングされます(私はそう思います)。

これにより、各ターミナルセッションには、起動から始まる独自の独立した履歴があります。さまざまなタスクのためにさまざまなターミナルを開く傾向があるので(そのため、それぞれでさまざまなコマンドを繰り返したいので)、さらに便利です。また、複数の端末が分散方式で常にordered履歴を再同期しようとしていることを理解するよりも、非常に簡単です(ただし、選択セッションでhistorymerge関数を使用して意図的にそれを行うことはできますが、それらすべて)。

必要な履歴の長さを保持するのに十分な大きさのサイズ制限が必要であることに注意してくださいplus同時にアクティブなすべてのセッションによって追加される重複排除されていないラインのボリューム。主にHISTIGNOREを使用してスパム性のある低価値のコマンドを除外しているおかげで、5000で十分です。

0
HonoredMule