web-dev-qa-db-ja.com

他のttyで実行されているシェルプロセスからbash履歴または最後のx数直線を取得する方法

興味深い小さなジレンマ。 Centosです。昨夜、ttyで物理コンソールにログインしました。コマンドを起動して、一晩実行させました。 ttyはまだログインしていますが、現在sshを介してリモートでログインしています(コンソールにはアクセスしていません)。

使用した正確なコマンドパラメーターを知りたいので(覚えていません)、そのttyで実行したコマンドを確認したいと思います。シェルはまだ実行されているため、bash_historyには何も書き込まれていません。そのインスタンスの履歴はまだメモリにあります。

だから、私の質問は、私が欲しいものをリモートで取得する方法があるかどうかです、おそらく:

(a)実行中のシェルにシグナルを送信し、bash履歴をダンプさせます(b)実行中のシェルの環境を調べて履歴情報を取得します(c)ttyセッションから最新のx行を調べて入力した内容がわかります

または他の手段..。

6

わかりました、わかりました。これは実際にはかなり気の利いたことです。多くの用途があると予測できます。

  1. リモートホストへのsshセッションを開きます。いくつかのウィンドウで画面またはtmuxセッションを起動します。 「tty」と入力すると、各ウィンドウの疑似デバイスを判別できます。スクリーンセッションで実行している3つのシェルに対応する「/ dev/pts/[123]」があるとします。

  2. 問題のbashプロセスのpid(入力と出力をリダイレクトするもの)を決定します。このプロセスは現在、/ dev/tty1などの端末デバイスに関連付けられています

  3. 画面ウィンドウ1から、「gdb -p [pid]」を実行し、gdb内で次のコマンドを実行します。

    a。 p dup2(open( "/ dev/pts/2"、0)、0)#これにより、ターゲットプロセスの標準入力が変更されます

    b。 p dup2(open( "/ dev/pts/3"、1)、1)#これにより、ターゲットプロセスの標準出力が変更されます

    c。 p dup2(open( "/ dev/pts/3"、1、)、2)#これにより、ターゲットプロセスの標準エラーが変更されます

    d。デタッチ

    e。終了する

つまり、ステップ3で行うことは、ウィンドウ2を標準入力にし、ウィンドウ3を出力にすることです。

4.ウィンドウ1(/ dev/pts/1)から、「ls -l/proc/[pid]/fd」を使用して、操作するbashプロセスのファイル記述子の変更を確認します。

5.ウィンドウ2に入力した内容は、このウィンドウに関連付けられた元のbashシェルとターゲットプロセスの2か所に送られます。したがって、ウィンドウ2(/ dev/pts/2)から、「hhiissttoorryy [return] [return]」と入力します。すべてを2回入力する必要がある理由は、入力が現在のbashシェルとターゲットのbashシェルの両方に分割されるためです。これは、オペレーティングが/ dev/pts/2のキーボード入力を利用している2つのソースがあることを認識しており、入力した文字を公平に分散するためです。最初の文字は1つの宛先に、次の文字は2番目の宛先に移動します。stdinが/ dev/pts/3であるプロセスが3つある場合、各文字を3回入力する必要があります。カーネルは、入力文字をラウンドロビン方式で受信者にフィードします。

6.元のWindow2 bashシェルのstdinを/ dev/tty5などの未使用のデバイスに一時的に設定することで、上記の不便を回避できます。これにより、/ dev/pts/2キーボードが(2つではなく)1つのプロセスのみの標準入力になります。これで、通常どおりコマンドを入力できます(コマンドは、現在の画面にエコーされません。代わりに/ dev/pts/3にエコーされます)。

7.'history 'と入力し、stdoutがウィンドウ3であるターゲットプロセスにフィードされたので、ウィンドウ3に切り替えて、コマンド出力を確認します。これで、ターゲットbashシェルのコマンド履歴ができました。

8.ウィンドウ1に戻り、[pid]でgdbを再度使用して、ターゲットシェルの標準のin、out、errを元の値(/ dev/tty1)にリセットします。また、Window 2stdinを本来の状態に戻すこともできます。

  1. 必要に応じて、「exec 3>&-」を使用して余分なファイル記述子を削除し、たとえばfd3を削除することで余分なファイル記述子をクリーンアップできます。

実行中のプロセスでgdbを実行すると、SIGSTOPと同じ方法でプロセスの実行が一時停止されることに注意してください。 「デタッチ」すると、SIGCONTのように再開します。これにより、悪影響を与えることなくファイル記述子を操作できます。

私は試していませんが、シェルを開き、そのttyまたはptyを決定し、シェルに割り当てられた標準を未使用のデバイスに一時的に設定し、tty /を割り当てることで、上記をさらに簡単でユーザーフレンドリーにすることができます。ターゲットシェルの標準の入力/出力としてpty。このようにして、ターゲットシェルでのすべての入力と出力に単一の画面を使用できます。

概要:上記の手順では、アクセスできるシェルがある限り、システム上の他のプロセス/シェルの標準の入出力として使用できます。これは、たとえば、コンソールで実行されているシェルと対話したいが、ホスト(または完全自動ソリューション)に物理的にアクセスできない場合に役立ちます。もちろん、これは、特定のシェルが選択したプロセスの入力/出力を制御するようにしたい、さまざまな状況に一般化できます。

3

私はまだこの状況に半定期的に直面しており、最終的に「孤立した」bashセッションからメモリ内の履歴コマンドを回復するためのより簡単な方法をいくつか思いつきました。

(注:以下の各例では、PIDを孤立したbashセッションのプロセスIDに置き換えます)

効果的にhistory -aをトリガーします:

$ gdb -p PID -batch -ex 'call maybe_append_history(get_string_value("HISTFILE"))'

最後の10個の履歴エントリをローカル端末にダンプします(pty)

$ gdb -p PID -batch -ex 'call append_history(10, "'$(tty)'")'

履歴全体を一時ファイルにバックアップします。

$ gdb -p PID -batch -ex 'call write_history("/tmp/history-backup.txt")'

ノート:

  • Ubuntu16.04.01でbash4.3を使用してテスト済み。
  • 私のシステムでは、自分のbashプロセスにアクセスするためにも、Sudo gdbを使用して呼び出す必要がありました。
  • 呼び出しが成功すると、$1 = 0が表示されます(他の値が表示されている場合は、おそらくerrnoです。たとえば、まだ存在しないファイルに追加しようとすると、$1 = 2(ENOENT)が表示されます) 。
  • このアプローチは、historyコマンドに応答してbashCコードが何を行うかを調査することに基づいています。例: builtins/history.def#L203-L212
2
humbletim