1. 概要

プロセス管理の一部として、Linuxのプロセスの子プロセスを取得する必要がある場合があります。

このチュートリアルでは、この目標を達成するためのいくつかの方法について説明します。 ここでは、プロセス識別子(PID)、スレッド識別子(TID)、および /procファイルシステムについて説明します。

2. テストシナリオの設定

チュートリアルの例としてシナリオを設定します。 このシナリオでは、親プロセスと子プロセスの両方があります。

child.shという名前のシェルスクリプトの作成から始めましょう。

#!/bin/bash
sleep infinity

このシェルスクリプトの目標は、このスクリプトを実行することによって生成されたプロセスが sleep infinity コマンドで待機するため、永久に実行されるプロセスを持つことです。 このスクリプトに加えて、parent.shという名前の別のシェルスクリプトがあります。

#!/bin/bash
./child.sh &
sleep infinity

このシェルスクリプトは、最初にスクリプトchild.shをバックグラウンドプロセスとして開始します。 次に、独自の sleepinfinityコマンドで永久に待機します。

それでは、スクリプトparent.shを実行してみましょう。

$ parent.sh &
[1] 6245

スクリプトparent.shを実行して生成されたプロセスのプロセスID(PID)は6245です。 チュートリアルの残りの部分で、このプロセスの子プロセスを見つけようとします。

3. pgrepコマンドの使用

子のプロセスを見つける簡単な方法は、pgrepコマンドを使用することです。 pgrep コマンドは、提供された検索条件に従って、現在実行中のプロセスを一覧表示します。 これらの検索条件にはいくつかのコマンドオプションが用意されており、-Pオプションもその1つです。 -P オプションは、PIDを取得することを想定しています。 このPIDは、子プロセスを検索する親プロセスのPIDです。 pgrep コマンドを使用して、PID6245のプロセスの子プロセスを確認してみましょう。

$ pgrep -P 6245
6246
6247

ご覧のとおり、PID6245のプロセスに対して2つのPIDを取得しました。 -l オプションを使用して、プロセス名を一覧表示できます。

$ pgrep -lP 6245
6246 child.sh
6247 sleep

実行したコマンドの出力から明らかなように、 pgrepコマンドは、親プロセスの直接の子プロセスをリストするだけです子プロセスの子、つまり間接の子はリストしません。プロセス。 この例では、PID 6246のプロセスの直接の子プロセスもあります。このプロセスは、スクリプトchild.shsleepinfinityコマンドを実行することによって生成されます。 ただし、PID 6245のプロセスの直接の子プロセスではないため、出力には表示されません。

4. pstreeコマンドの使用

pstree コマンドは、親プロセスの子プロセスを表示するためにも使用できます。 -pオプションでPIDを取ります。 -p オプションに指定されたPIDは、親プロセスのPIDとして使用されます。 親プロセスの子プロセスをツリーとして表示します。 pstree コマンドを使用して、PID6245のプロセスの子プロセスを確認してみましょう。

$ pstree -p 6245
parent.sh(6245)---child.sh(6246)---sleep(6248)
                |-sleep(6247)

pstreeコマンドは、直接の子プロセスだけでなく、間接の子プロセスもツリーとして表示します。 PID6247および6248のsleepプロセスは、スクリプトparent.shおよびchild.sh[でsleepinfinityステートメントを実行することによって作成されたプロセスです。 X179X]、それぞれ。

-p オプションの代わりに、 –parentオプションを使用することもできます。 それらはまったく同じです。

5. psコマンドの使用

ps コマンドは、現在実行中のプロセスとそのPIDを一覧表示します。 –ppidオプションをps コマンドに渡して、子プロセスを見つけることができます。 このオプションは、 pgrep コマンドと同様に、PIDを取得することを想定しています。 このPIDは、子プロセスを検索する親プロセスのPIDです。 それでは、 ps コマンドを使用して、PID6245のプロセスの子プロセスを見つけましょう。

$ ps --ppid 6245
 PID TTY          TIME CMD
6246 pts/1    00:00:00 child.sh
6247 pts/1    00:00:00 sleep

ps コマンドの出力をフォーマットして、PID、親PID、およびコマンドのみを出力できます。

$ ps --ppid 6245 -o pid,ppid,cmd
 PID  PPID CMD
6246  6245 /bin/bash ./child.sh
6247  6245 sleep infinity

psコマンドの出力は、pgrepコマンドの出力と似ています。間接的な子プロセスはリストされませんが、直接的な子プロセスのみがリストされます。 この例では、PID 6246のプロセスの子プロセスがありますが、出力には表示されません。 これは、 sleepinfinityコマンドを実行することによってスクリプトchild.shが生成したプロセスです。

6. /procファイルシステムの使用

/ proc ディレクトリを使用して、親プロセスの子プロセスを見つけることもできます。 実際、これはディレクトリではなく、システムによって自動的に /procにマウントされる仮想ファイルシステムです。 カーネル、システム、およびプロセスに関する情報が含まれています。

親プロセスの子プロセスのPIDは、 / proc / [pid] / task /[tid]ディレクトリにあるchildrenファイルにあります。 ディレクトリ構造について少し説明しましょう。

パスの[pid]部分から始めましょう。 / proc ディレクトリには、実行中のプロセスごとに1つのサブディレクトリが含まれています。 各サブディレクトリの名前は、対応するプロセスのPIDです。

プロセスのスレッドごとに、 / proc / [pid] /taskディレクトリに1つの[tid]サブディレクトリがあります。 したがって、このサブディレクトリの名前を [tid] (スレッドID)と呼びました。 メインスレッドに対応するサブディレクトリは、プロセスのPIDと同じです。

これまでの説明を念頭に置いて、この例のディレクトリ構造を調べてみましょう。

$ ls /proc/6245/task
6245
$ cat /proc/6245/task/6245/children
6246 6247

parent.shスクリプトを実行して取得したプロセス用のディレクトリ/proc /6245があります。 プロセスはマルチスレッドではないため、ディレクトリは / proc / 6245 / task / 6245、の1つだけです。 PID 6245の親プロセスの子プロセスのPIDは、 / proc / 6245 / task / 6245 / children ファイル、つまり6246および6247にあります。

同じ方法で検査を続けることができます:

$ ls /proc/6246/task
6246
$ cat /proc/6246/task/6246/children
6248
$ ls /proc/6248/task
6248 
$ cat /proc/6248/task/6248/children
$ ls /proc/6247/task
6247
$ cat /proc/6247/task/6247/children

上記のコマンドの実行の出力からわかるように、PID6246のプロセスには子が1つだけあります。 そのPIDは6248です。 PID 6247および6248のプロセスには、子プロセスはありません。 これらのプロセスに対応するchildrenファイルは空です。 したがって、取得した子プロセスは、pstreeコマンドを実行して取得したものと同じです。

シェルスクリプト、つまり find_children.sh を使用して、上記の再帰プロセスを自動化できます。

#!/bin/bash

# root_pid: The PID passed to the script
# That is the PID of the process whose child processes we want to find
root_pid=$1

# all_children: Array that shall store the child processes
declare -A all_children
all_children=()

# Recursive function to find the child processes 
iterate_children()
{
   local pid=$1
   local tids=$(ls /proc/$pid/task)
   # Iterate over all [tid]s in /proc/$pid/task directory
   for tid in $tids
   do
      if [ -e /proc/$pid/task/$tid/children ]
      then
         # Get the child processes in /proc/$pid/task/$tid/children
         local children=$(cat /proc/$pid/task/$tid/children)
         # Iterate over all child processes
         for p in $children
         do
            # Add the found child process to all_children array 
            all_children[${#all_children[@]}]=$p
            # Find the child processes of process $p
            iterate_children $p
         done
      fi
   done
}

iterate_children $root_pid
echo "All child processes of process with PID $root_pid:"
echo ${all_children[*]}

このスクリプトを実行すると、同じ結果が得られます。

$ ./find_children 6245
All child processes of process with PID 6245:
6246 6248 6247

7. 結論

このチュートリアルでは、プロセスの子プロセスを取得するいくつかの方法について説明しました。 pgrepおよびpsコマンドは、親プロセスの直接の子プロセスを見つけるのに役立ちます。 pstree コマンドは、ツリー構造内のすべての直接および間接の子プロセスを一覧表示します。 親プロセスの子プロセスは、 /procファイルシステムで再帰的に見つけることもできます。 また、 /procファイルシステムを使用してすべての子プロセスを自動的に検索するためのシェルスクリプトも提供しました。