pgrep -P, но для внуков не просто детей - PullRequest
0 голосов
/ 26 сентября 2018

Я использую:

pgrep -P $$

, чтобы получить детские пособия в размере $$.Но на самом деле мне нужен список внуков и правнуков.

Как мне это сделать?С обычным языком программирования мы сделали бы это, например, с помощью рекурсии, но с помощью bash?Возможно использовать функцию bash?

Ответы [ 6 ]

0 голосов
/ 02 октября 2018

Я сделал это с помощью node.js и bash:

 const async = require('async');
 const cp = require('child_process');

 export const getChildPids = (pid: number, cb: EVCb<Array<string>>) => {

      const pidList: Array<string> = [];

      const getMoreData = (pid: string, cb: EVCb<null>) => {

        const k = cp.spawn('bash');
        const cmd = `pgrep -P ${pid}`;
        k.stderr.pipe(process.stderr);
        k.stdin.end(cmd);
        let stdout = '';
        k.stdout.on('data', d => {
          stdout += String(d || '').trim();
        });

        k.once('exit', code => {

          if (code > 0) {
            log.warning('The following command exited with non-zero code:', code, cmd);
          }

          const list = String(stdout).split(/\s+/).map(v => String(v || '').trim()).filter(Boolean);

          if (list.length < 1) {
            return cb(null);
          }

          for (let v of list) {
            pidList.push(v);
          }

          async.eachLimit(list, 3, getMoreData, cb);

        });
      };

      getMoreData(String(pid), err => {
        cb(err, pidList);
      });

    };
0 голосов
/ 27 сентября 2018

Я уже опубликовал попытку решения .Он короткий и эффективный, и, кажется, соответствует вопросу ОП, поэтому я оставлю все как есть.Однако у него есть некоторые проблемы с производительностью и переносимостью, которые означают, что это не очень хорошее общее решение.Этот код пытается решить проблемы:

top_pid=$1

# Make a list of all process pids and their parent pids
ps_output=$(ps -e -o pid= -o ppid=)

# Populate a sparse array mapping pids to (string) lists of child pids
children_of=()
while read -r pid ppid ; do
    [[ -n $pid && pid -ne ppid ]] && children_of[ppid]+=" $pid"
done <<< "$ps_output"

# Add children to the list of pids until all descendants are found
pids=( "$top_pid" )
unproc_idx=0    # Index of first process whose children have not been added
while (( ${#pids[@]} > unproc_idx )) ; do
    pid=${pids[unproc_idx++]}       # Get first unprocessed, and advance
    pids+=( ${children_of[pid]-} )  # Add child pids (ignore ShellCheck)
done

# Do something with the list of pids (here, just print them)
printf '%s\n' "${pids[@]}"

Базовый подход использования поиска в ширину для построения дерева был сохранен, но основная информация о процессах получается с помощью одного (POSIX-соответствует) пробег ps.pgrep больше не используется, потому что его нет в POSIX, и его можно запускать много раз.Кроме того, очень неэффективный способ удаления элементов из очереди (копирование всех элементов, кроме одного) был заменен манипулированием индексной переменной.

Среднее (реальное) время выполнения равно 0,050 с при запуске на pid0 в моей старой системе Linux с около 400 процессами.

Я тестировал ее только в Linux, но она использует только функции Bash 3 и POSIX-совместимые функции ps, поэтому она должна работать и в других системах..

0 голосов
/ 26 сентября 2018

Использование только встроенных команд bash (даже не ps или pgrep!):

#!/usr/bin/env bash

collect_children() {
  # format of /proc/[pid]/stat file; group 1 is PID, group 2 is its parent
  stat_re='^([[:digit:]]+) [(].*[)] [[:alpha:]] ([[:digit:]]+) '

  # read process tree into a bash array
  declare -g children=( )              # map each PID to a string listing its children
  for f in /proc/[[:digit:]]*/stat; do # forcing initial digit skips /proc/net/stat
    read -r line <"$f" && [[ $line =~ $stat_re ]] || continue
    children[${BASH_REMATCH[2]}]+="${BASH_REMATCH[1]} "
  done
}

# run a fresh collection, then walk the tree
all_children_of() { collect_children; _all_children_of "$@"; }

_all_children_of() {
  local -a immediate_children
  local child
  read -r -a immediate_children <<<"${children[$1]}"
  for child in "${immediate_children[@]}"; do
    echo "$child"
    _all_children_of "$child"
  done
}

all_children_of "$@"

В моей локальной системе time all_children_of 1 >/dev/null (вызывая функцию в уже запущенной оболочке) синхронизируетв окрестности 0,018 с - обычно 0,013 с для этапа collect_children (одноразовое действие чтения дерева процессов) и 0,05 с для рекурсивного обхода этого дерева, инициированного начальным вызовом _all_children_of.

В предыдущие периоды времени тестировалось только время, необходимое для прогулки, без учета времени, необходимого для сканирования.

0 голосов
/ 26 сентября 2018

Код ниже напечатает PID текущего процесса и всех его потомков.Он использует массив Bash в качестве очереди для реализации поиска в ширину дерева процессов.

unprocessed_pids=( $$ )
while (( ${#unprocessed_pids[@]} > 0 )) ; do
    pid=${unprocessed_pids[0]}                      # Get first elem.
    echo "$pid"
    unprocessed_pids=( "${unprocessed_pids[@]:1}" ) # Remove first elem.
    unprocessed_pids+=( $(pgrep -P $pid) )          # Add child pids
done
0 голосов
/ 26 сентября 2018

Если pgrep не делает то, что вы хотите, вы всегда можете использовать ps напрямую.Опции будут в некоторой степени зависеть от платформы.

ps -o ppid,pid |
awk -v pid=$$ 'BEGIN { parent[pid] = 1 }  # collect interesting parents
    { child[$2] = $1 }  # collect parents of all processes
    $1 == pid { parent[$2] = 1 }
    END { for (p in child)
        if (parent[child[p]])
          print p }'

Имена переменных не ортогональны - parent собирает процессы, которые pid или один из его дочерних элементов, в качестве ключей, то есть "интересных" родителейи child содержит родительский элемент каждого процесса, ключом которого является процесс, а родительским значением - значение.

0 голосов
/ 26 сентября 2018

Возможно, простой цикл сделает это:

# set a value for pid here
printf 'Children of %s:\n' $pid
for child in $(pgrep -P $pid); do
    printf 'Children of %s:\n' $child
    pgrep -P $child
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...