web-dev-qa-db-ja.com

ps:どこようにして与えられたpidのすべての子プロセスを再帰的に取得することができますか

特定のプロセスによって生成されたプロセスツリー全体をツリーとして表示し、そのツリーのみを表示する方法、つまり他のプロセスを表示しない方法を教えてください。

出力は、例えば、のように見える

 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`

誰かがより簡単な解決策を持っていますか?

40
kynan

pstreeは非常に良い解決策ですが、それは少し謙虚です。代わりにps --forestを使用します。しかしPID-p)には適していません。特定のプロセスだけを表示するのであり、セッション(-g)には表示しないためです。 ps-oオプションを定義する派手なASCIIアートツリーに印刷できる任意の情報を印刷できます。

だからこの問題について私の提案:

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

残念ながら、これはそれぞれの子スクリーンとすべての孫のbashのsidを設定するのでscreenには機能しません。

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

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
32
TrueY
pstree ${pid}

$ {pid}は親プロセスのPIDです。

Gentooでは、pstreeは "psmisc"パッケージ内にあり、明らかに http://psmisc.sourceforge.netにあります。 /

24
Eroen

これは私のバージョンです(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
)
10
xzfc

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

ツリー自体を追加するのではなく、単なるプロセスのリストです。

例えば

COMMAND
bash
  nvim
    python
3
edi9999

私はまったく同じ問題に対する解決策を見つけるために努力してきました。基本的に、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
}
3
Philippe A.

私は親の子プロセスのリスト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です

3
Merijn

これはpid + children pidのみをそれぞれ1行に与えます。

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

コマンドラインでの作業中:

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
Shakiba Moshiri

上記の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 $(pidlistpid

0
kylehutson