ps:特定のpidのすべての子プロセスを再帰的に取得する方法


43

特定のプロセスによって生成されたプロセスツリー全体をツリーとして表示し、そのツリーのみ、つまり他のプロセスを表示しないようにするにはどうすればよいですか?

出力は次のようになります。

 4378 ?        Ss     0:10 SCREEN
 4897 pts/16   Ss     0:00  \_ -/bin/bash
25667 pts/16   S+     0:00  |   \_ git diff
25669 pts/16   S+     0:00  |       \_ less -FRSX
11118 pts/32   Ss+    0:00  \_ -/bin/bash
11123 pts/32   S+     0:00      \_ vi

へのパラメータだけでは、目的の結果を得ることができませんでしたps

以下は望ましい結果を与えますが、少し複雑に思われます:

#!/bin/bash

pidtree() {
  echo -n $1 " "
  for _child in $(ps -o pid --no-headers --ppid $1); do
    echo -n $_child `pidtree $_child` " "
  done
}

ps f `pidtree 4378`

誰でも簡単な解決策がありますか?


答えではありませんが、で始まりps auxfます。
jftuga

3
@jtfugaこれは私が始めた、実際にあるが、これは私に与え、すべて私が正確に何である、プロセスをしませんしたいです。
キナン

回答:


38

これpstreeは非常に良いソリューションですが、少し控えめです。ps --forest代わりに使用します。ただし、特定のプロセスのみを出力するため、PID-p)ではなく、セッション(-g)についてです。オプションをps定義する豪華なASCIIアートツリーで印刷できる情報を印刷でき-oます。

したがって、この問題に対する私の提案:

ps --forest -o pid,tty,stat,time,cmd -g 2795

プロセスがセッションリーダーでない場合、もう少しトリックを適用する必要があります。

ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)

これは、最初に現在のプロセスのセッションID(SID)を取得してから、そのsidで再度psを呼び出します。

列ヘッダーが不要な場合、「-o」オプションの各列定義の後に「=」を追加します。

ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 2795)

実行例と結果:

$ ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 30085)
27950 pts/36   Ss   00:00:00 -bash
30085 pts/36   S+   00:00:00  \_ /bin/bash ./loop.sh
31888 pts/36   S+   00:00:00      \_ sleep 5

残念ながら、screen各子画面とすべての孫bashにsidを設定するため、これは機能しません。

プロセスによって生成されるすべてのプロセスを取得するには、ツリー全体を構築する必要があります。そのためにを使用しました。最初に、allを含むハッシュ配列を作成しますPID => ,child,child...。最後に、再帰関数を呼び出して、特定のプロセスのすべての子プロセスを抽出します。結果は別の結果に渡されps、結果がフォーマットされます。実際のPIDは、次の代わりに引数として記述する必要があります<PID>

ps --forest $(ps -e --no-header -o pid,ppid|awk -vp=<PID> 'function r(s){print s;s=a[s];while(s){sub(",","",s);t=s;sub(",.*","",t);sub("[0-9]+","",s);r(t)}}{a[$2]=a[$2]","$1}END{r(p)}')

SCREENプロセス(pid = 8041)の場合、出力例は次のようになります。

  PID TTY      STAT   TIME COMMAND
 8041 ?        Ss     0:00 SCREEN
 8042 pts/8    Ss     0:00  \_ /bin/bash
 8092 pts/8    T      0:00      \_ vim test_arg test_server
12473 pts/8    T      0:00      \_ vim
12972 pts/8    T      0:00      \_ vim

これに関する問題(私は知っている、それは古い答えだ)は、--forestオプションがLinux(または他のgnuベースの「ps」コマンド)でのみ機能することです。Solaris、およびMacOSはそれを好みません。
アルマン

@TrueYそれができるC APIを知っていますか?ありがとう
Bionix1441

Bionixいいえ、申し訳ありません... / proc / <PID>ディレクトリを読み取って、そのツリーを構築できます。
TrueY

1
psPIDのすべての子孫にフィルタリングするためのフィルターフラグオプションがあれば、これは簡単なはずです。
CMCDragonkai

27
pstree ${pid}

ここ${pid}で、親プロセスのpidです。

Gentoo Linuxでは、pstreeパッケージ「psmisc」に含まれています。http://psmisc.sourceforge.net/


9
おかげで、私が見ていたことを言及すべきpstreeだったが、より詳細な出力形式を見逃した。ただし、pstree -p <pid>少なくとも合理的に近いpidを出力します。
キナン

2
私は私がしなければならないので、私は再帰的にすべての子PIDを収集する必要があるが、私は唯一のPIDを必要とする、あまりにもこの問題を持っているsedすべてのこと...うーん、この作品を:)pstree -pn 4008 |grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*"
アクエリアスパワー

12

これは即座にps実行されるバージョンです(一度だけ実行されるため)。bashとzshで動作します。

pidtree() (
    [ -n "$ZSH_VERSION"  ] && setopt shwordsplit
    declare -A CHILDS
    while read P PP;do
        CHILDS[$PP]+=" $P"
    done < <(ps -e -o pid= -o ppid=)

    walk() {
        echo $1
        for i in ${CHILDS[$1]};do
            walk $i
        done
    }

    for i in "$@";do
        walk $i
    done
)

1
これは、現在のプロセスのpidも出力します。現在のプロセス(現在のプロセスの子孫のみ)を一覧表示したくないためecho $1、最初のforループ内に移動してに変更することでスクリプトを変更しましたecho $i
マークラカタ

1
これを見つけたとき、私はちょうどそのような関数を書き込もうとしていました。これは、MacOS、Linux、およびSolarisで動作するように見える唯一のソリューションです。すごい仕事。1回のpsの実行に依存してジョブをメモリ内で実行できることを愛します。
アルマン

3

親の子プロセスのリストPIDを作成する小さなbashスクリプトを作成しました。子を持たない最後の子プロセスを見つけるまで再帰的に。ツリービューは表示されません。すべてのPIDをリストするだけです。

function list_offspring {
  tp=`pgrep -P $1`          #get childs pids of parent pid
  for i in $tp; do          #loop through childs
    if [ -z $i ]; then      #check if empty list
      exit                  #if empty: exit
    else                    #else
      echo -n "$i "         #print childs pid
      list_offspring $i     #call list_offspring again with child pid as the parent
    fi;
  done
}
list_offspring $1

list_offspringの最初の引数は親pidです


1
実際のツリーを印刷しないbashスクリプトを提供する他のいくつかの回答が既にあります。質問自体の回答も含まれます。既存の(部分的な)答えに対して(部分的な)答えにはどのような利点があるのですか
デビッドリチャービー

再帰を使用して説明を追加しました。それは誰かを助けるかもしれないと思った。タイトルが求めるものを正確に実行します。
メレイン

ここでpgrepの使用が好きです。なぜなら、psはunixのバリアントによって異なる可能性があるからです。
ジョンシャクマイスター16

3

ps -H -g "$pid" -o comm

ツリー自体を追加するのではなく、プロセスのリストにすぎません。

例えば

COMMAND
bash
  nvim
    python

この-Hオプションは、プロセスツリーまたは「プロセス階層(フォレスト)」
アンソニーG-モニカの正義

2

私はまったく同じ問題の解決策を見つけるために取り組んできました。基本的に、psマンページには、1つのコマンドで必要なことを実行できるオプションは記載されていません。結論:スクリプトが必要です。

あなたと非常によく似たスクリプトを思いつきました。〜/ .bashrcに貼り付けたので、どのシェルからでも使用できます。

pidtree() {
  local parent=$1
  local list=
  while [ "$parent" ] ; do     
    if [ -n "$list" ] ; then
      list="$list,$parent"
    else
      list="$parent"
    fi
    parent=$(ps --ppid $parent -o pid h)
  done
  ps -f -p $list f
}

1

コマンドラインでの途中:

ps -o time,pid,ppid,cmd --forest -g -p $(pgrep -x bash)

以下を出力します:

    TIME   PID  PPID CMD
00:00:00  5484  5480 bash
00:00:01  5531  5484  \_ emacs -nw .bashrc
00:00:01  2986  2984 /bin/bash
00:00:00  4731  2986  \_ redshift
00:00:00  5543  2986  \_ ps -o time,pid,ppid,cmd --forest -g -p 2986 5484

その方法のよりエレガントな方法は、関数を.bashrc次のように定義することです。

function subps()                                                                                    
{                                                                                                   
    process=$(pgrep -x $1)                                                                                                                                                                     
    ps -o time,pid,ppid,cmd --forest -g -p $process                                                 
}    

次に、コマンドラインで次を実行します。

subps bash

1

これにより、各行にpid +子pidのみが追加され、さらに処理するのに役立ちます。

pidtree() {
    for _pid in "$@"; do
        echo $_pid
        pidtree `ps --ppid $_pid -o pid h`
    done
}

0

上記のPhilippeに基づいて同様のスクリプトを作成しました

pidlist() {
local thispid=$1
local fulllist=
local childlist=
childlist=$(ps --ppid $thispid -o pid h)
for pid in $childlist
do
  fulllist="$(pidlist $pid) $fulllist"
done
echo "$thispid $fulllist"
}

これにより、すべての子、孫などのpidがスペース区切り形式で出力されます。これは、次のように、psに渡すことができます

ps -p $(pidlist pid


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