to get the child pids of $$. But I actually want a list of grandchildren and great grandchild too.
Since I am using the following (bash 5.1.16) I thought I'd share in case its useful for others as it is pretty short:
get_all_descendants() {
declare -n children="children_${1}"
mapfile -t children < <(pgrep -P "${1}")
for child in "${children[@]}"; do
echo "${child}"
get_all_descendants "${child}"
done
}
Sample usage:
declare -a children < <(get_all_descendants $PPID)
for child in "${children[@]}"; do
echo "${child}"
done
How do I do this tho? With a regular programming language we would do that with recursion for example, but with bash? Perhaps use a bash function?
As you can see with the sample above, you can recurse in bash. Variable scope in bash can sometimes be tricky, with unintended consequences.
get_all_descendants
takes a single parameter, the PID to find descendants.
It declares a variable reference using the passed PID to decorate the variable name via declare -n children="children_${1}"
.
It then uses pgrep
to obtain the children of the requested pid (${1}
), using mapfile -t children
to populate the referenced array children
.
It then loops through the children, echo'ing the child's pid, and then recurses with each child.
It isn't the fastest solution due to all the subprocess launching (mapfile, psgrep) but it is simple and seems robust. Running on my system:
start_pid=$(bash -c 'echo $$') ; \
time get_all_descendants 0 | wc -l ; \
end_pid=$(bash -c 'echo $$') ; \
echo "Subprocesses launched: $((end_pid-start_pid))"
695
real 0m11.010s
user 0m3.183s
sys 0m7.946s
Subprocesses launched: 1396
The fastest solution you could is more code-complex, and at best would approach ps aux
speeds:
start_pid=$(bash -c 'echo $$') ; \
time ps aux | wc -l ; \
end_pid=$(bash -c 'echo $$') ; \
echo "Subprocesses launched: $((end_pid-start_pid))"
695
real 0m0.043s
user 0m0.016s
sys 0m0.031s
Subprocesses launched: 3
However, I don't need speed, and code manageability is more important for where this is being used.