web-dev-qa-db-ja.com

ログインごとにBASH履歴が500行に切り捨てられました

何らかの理由で、再起動後にシステムに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行がありません。

誰かが文句を言う前に、はい、私はこれらの質問を読みました。上記の提案のいくつかを実装しましたが、残りは役に立たなかったか、関連性がありませんでした。

他の関連コマンドが存在する可能性がある場合は、~/.bashrchere 全体を表示できます。

だから、私は何が欠けていますか?履歴が保存されないのはなぜですか?別のファイルが関連していると思われる場合はお知らせください。投稿します。 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をデフォルトの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

では、~/.bashrcをデフォルトの$HISTFILE以外に明示的に設定しない限り、~/.bash_historyHISTSIZEHISTFILESIZEを設定するだけでは不十分なのはなぜですか。

22
terdon

問題は、実際には、ログインシェルと非ログインシェルの 異なる動作 に要約されます。私は~/.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変数のみを設定したため、異なるタイプのシェルを実行するたびに変数が無視され、ファイルはそれに応じてカットされます。

17
terdon

私の提案は、デフォルトの~/.bash_historyではなく、HISTFILEとして別のファイルを使用することです。

分析的な説明はありませんが、この提案につながった理由の概要を説明します。デフォルトの(ログイン)シェルとしてbashを使用し、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構成からの詳細でより正当な説明を投稿することはできません...

12
mpy

すべての設定はマニュアルページに従って行われ、履歴ファイルはサイズ(バイト)によって制限されていないため、考えられる唯一の説明です。それはシェルがどのように死ぬかと関係があります。

オンラインリファレンスによると、正常な終了(履歴が保存された)は、シェルがSIGHUPを受信したときにのみ発生します。再起動時にシステムがどのようにシグナルを伝播するかを実際に説明することはできませんが、シェルがSIGKILLまたはSIGPWRで終了したと思われます。

WMが非同期で実行され(待機)、bashが存在するWMからターミナルエミュレータが生成され、SIGHUP以外の終了強制信号を取得したことが原因である可能性があります。 XまたはWM-> xtermを介してシェルに到達するには、最初の優雅なSIGHUPが管理する前に、OSがすべてのプロセスにすばやく「最終キル」を送信することも考えられます。 OSがダウンする準備が整うまでに時間がかかります。

私はこのようなもので深海にいますが、それらの線に沿った何かが不安定な動作を引き起こすと思います。私は以前にこの問題を抱えていましたが、最も確実な救済策は、履歴を保持したいbashのexitです。

私は気づきました 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...

含まれているスクリーンショットは、2番目と3番目の段落で私が話していることを示しています。左からにIシェルがあるシーケンス、右から左のシェルを殺し、履歴をキャットします。

man bash

起動時に、(...)HISTFILEの値で指定されたファイルは、HISTFILESIZEの値で指定された行数(+デフォルトは500)以下になるように、必要に応じて切り捨てられます。

Histappend Shellオプションが有効になっている場合(+ここではデフォルト)、行は履歴ファイルに追加されます。有効になっていない場合、履歴ファイルは上書きされます。

オンライン参照

3.7.6信号

Bashがインタラクティブである場合、トラップがない場合、SIGTERMを無視し(「kill0」がインタラクティブシェルを強制終了しないように)、SIGINTをキャッチして処理します(待機ビルトインが中断可能になるように)。 BashがSIGINTを受信すると、実行中のループから抜け出します。すべての場合において、BashはSIGQUITを無視します。ジョブ制御が有効な場合(ジョブ制御を参照)、BashはSIGTTIN、SIGTTOU、およびSIGTSTPを無視します。

Bashによって開始された非組み込みコマンドには、シェルがその親から継承した値に設定されたシグナルハンドラーがあります。ジョブ制御が有効になっていない場合、非同期コマンドは、これらの継承されたハンドラーに加えて、SIGINTおよびSIGQUITを無視します。コマンド置換の結果として実行されるコマンドは、キーボードで生成されたジョブ制御信号SIGTTIN、SIGTTOU、およびSIGTSTPを無視します。

シェルは、SIGHUPを受信するとデフォルトで終了します。終了する前に、対話型シェルは、実行中または停止中のすべてのジョブにSIGHUPを再送信します。停止したジョブはSIGCONTに送信され、SIGHUPを確実に受信します。シェルがSIGHUPシグナルを特定のジョブに送信しないようにするには、disownビルトイン(ジョブコントロールビルトインを参照)を使用してジョブテーブルから削除するか、disown-hを使用してSIGHUPを受信しないようにマークする必要があります。

Huponexit Shellオプションがshoptで設定されている場合(The Shopt Builtinを参照)、インタラクティブログインシェルが終了すると、BashはすべてのジョブにSIGHUPを送信します。

Bashがコマンドの完了を待機していて、トラップが設定されている信号を受信した場合、コマンドが完了するまでトラップは実行されません。 Bashがwaitビルトインを介して非同期コマンドを待機している場合、トラップが設定されている信号を受信すると、待機ビルトインは終了ステータスが128を超えてすぐに戻り、その直後にトラップが実行されます。

デモ用スクリーンショット

signals

/ etc/profileと/etc/profile.d/*を確認してください

たぶん、そこに履歴設定を台無しにする何かがあります。

0
mabagu