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