いくつかのbashインスタンス内で実行されている正確なコマンドラインを確認するにはどうすればよいですか?


29

ループ内で複雑な一連のコマンドを実行しているbashscreenセッション内で)長時間実行されているインスタンスがあります(各ループはパイプ、リダイレクトなどを実行します)。

長いコマンドラインはターミナル内に記述されました-スクリプト内にはありません。これで、bashプロセスIDがわかりました。ルートアクセス権がありbashます。その中で実行されている正確なコマンドラインを確認するにはどうすればよいですか。

bash$ echo $$
1234
bash$ while true ; do \
    someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done

そして、別のシェルインスタンスで、PID 1234内で実行されたコマンドラインを表示したいです。

bash$ echo $$
5678
bash$ su -
sh# cd /proc/1234
sh# # Do something here that will display the string  \
   'while true ; do someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done'

これは可能ですか?

編集#1

私が持っているいくつかの答えに反例を追加します。

  1. cmdlineunderの使用について/proc/PIDは、少なくとも私のシナリオでは機能しません。以下に簡単な例を示します。

    $ echo $$
    8909
    
    $ while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done
    

    別のシェルで:

    $ cat /proc/8909/cmdline
    bash
    
  2. 使用することps -p PID --noheaders -o cmdは無意味です:

    $ ps -p 8909 --no-headers -o cmd
    bash
    
  3. ps -eaf 役に立たない:

    $ ps -eaf | grep 8909
    ttsiod    8909  8905  0 10:09 pts/0    00:00:00 bash
    ttsiod   30697  8909  0 10:22 pts/0    00:00:00 sleep 30
    ttsiod   31292 13928  0 10:23 pts/12   00:00:00 grep --color=auto 8909

    つまり、ORIGINALコマンドラインの出力はありません。これは、私が探しているものですwhile true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

回答:


40

ストローを把握していることは知っていましたが、UNIXは決して失敗しません!

私がそれを管理した方法は次のとおりです。

bash$ gdb --pid 8909
...
Loaded symbols for /lib/i386-linux-gnu/i686/cmov/libnss_files.so.2
0xb76e7424 in __kernel_vsyscall ()

次に、(gdb)プロンプトでコマンドを実行し、call write_history("/tmp/foo")この履歴をファイルに書き込みます/tmp/foo

(gdb) call write_history("/tmp/foo")
$1 = 0

その後、プロセスから切り離します。

(gdb) detach
Detaching from program: /bin/bash, process 8909

そして終了しgdbます。

(gdb) q

そして確かに...

bash$ tail -1 /tmp/foo
while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

将来の再利用を容易にするために、プロセスを自動化するbashスクリプトを作成しました


1
非常に良い調査を+1します。2日以内にこれを例外Aとしてマークしてください。
slm

@slm:ありがとう!私はそれについてのブログ記事を書きます-楽しかったので、これを追い詰めました。
ttsiodras 14年

1
readlineのが有効になってあなたもでこれを行うことができますgdbprint (char *)rl_line_buffer。シーケンス内の現在のコマンドは print (char *)the_printed_commandです。またcall history_builtin()、可能性がありますが、それはbashプロセスのttyに出力されるため、あまり有用ではありません。
Mr.spuratic 14年

11
@slm:抵抗できませんでした-私はそれについてここにブログしました:users.softlab.ece.ntua.gr/~ttsiod/bashheimer.html
ttsiodras

1
bashはスレッドセーフですか?gdbから何かを実行するときに、現在実行中のコードを混乱させる内部状態を変更しないことを期待する必要があります。実際には、bashは、gdbを使用して一時停止するたびに、子プロセスが終了するのをほぼ確実に待っています。
エイドリアンプロンク14年

5

コマンドはまだ画面で実行されているため、親bashは履歴を再読み取りしていません。

  • 画面に再接続する
  • プレス^Zその後、up arrow
  • ボーナス:コマンドを一重引用符で囲み(^A^A-(screen(1)-および^E)でナビゲート)、エコー+ファイルにリダイレクト
  • fg コマンドの実行を追求する

警告がありますが、ほとんどの場合、これは十分に役立ちます。


はい、それを殺してを押しupます。問題なく再起動すると確信する必要がありますが、再起動しない場合は、とにかく再起動後に同じ問題が発生します。ダウンタイムが問題にならない瞬間を選択するだけです。
マチューナポリ14年

0

あなた自身の答えを見つけたのは知っていますが、このようなことをできない理由があります:

(set -x; for f in 1 2 3 4 ; do  echo "$f"; sleep $f; done)

おそらく、実際のジョブの出力と現在実行中の行を示すbashの出力を混ぜることはできません。

また、FWIW、冗長性を好む場合、set -o xtrace

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.