Elegantly get list of descendant processes












22














I would like to get a list of all the processes that descend (e.g. children, grand-children, etc) from $pid. This is the simplest way I've come up with:



pstree -p $pid | tr "n" " " |sed "s/[^0-9]/ /g" |sed "s/ss*/ /g"


Is there any command, or any simpler way to get the full list of all descendant processes?










share|improve this question
























  • Is there a reason you need them all on one line? What are you doing with that output? I have a feeling that this is an xy problem, and you are asking the wrong question.
    – jordanm
    Mar 12 '13 at 17:03










  • I don't care about the format as long as it's clean (i.e. I don't care about 'n' delimited vs. ' ' delimited). Practical use case is: a) a daemonizer script I wrote out of pure masochism (specifically, the "stop" functionality has to deal with whatever tree of processes the daemonized process spawned); and b) a timeout script that will kill whatever the timed-out process managed to create.
    – STenyaK
    Mar 12 '13 at 21:06






  • 2




    @STenyaK Your use cases make me think you're looking for process groups and a negative argument to kill. See unix.stackexchange.com/questions/9480/…, unix.stackexchange.com/questions/50555/…
    – Gilles
    Mar 12 '13 at 21:51










  • @Gilles using ps ax -opid,ppid,pgrp,cmd I see there are many processes that share the same pgrp as the exact subtree I want to kill. (Additionally, I can't see the setpgrp program listed anywhere in debian stable packages: packages.debian.org/… )
    – STenyaK
    Mar 13 '13 at 7:42






  • 1




    Another use case: renice/ionice on a whole process tree that's eating too many resources, e.g. a large parallel build.
    – Cheetah
    Sep 25 '13 at 4:02
















22














I would like to get a list of all the processes that descend (e.g. children, grand-children, etc) from $pid. This is the simplest way I've come up with:



pstree -p $pid | tr "n" " " |sed "s/[^0-9]/ /g" |sed "s/ss*/ /g"


Is there any command, or any simpler way to get the full list of all descendant processes?










share|improve this question
























  • Is there a reason you need them all on one line? What are you doing with that output? I have a feeling that this is an xy problem, and you are asking the wrong question.
    – jordanm
    Mar 12 '13 at 17:03










  • I don't care about the format as long as it's clean (i.e. I don't care about 'n' delimited vs. ' ' delimited). Practical use case is: a) a daemonizer script I wrote out of pure masochism (specifically, the "stop" functionality has to deal with whatever tree of processes the daemonized process spawned); and b) a timeout script that will kill whatever the timed-out process managed to create.
    – STenyaK
    Mar 12 '13 at 21:06






  • 2




    @STenyaK Your use cases make me think you're looking for process groups and a negative argument to kill. See unix.stackexchange.com/questions/9480/…, unix.stackexchange.com/questions/50555/…
    – Gilles
    Mar 12 '13 at 21:51










  • @Gilles using ps ax -opid,ppid,pgrp,cmd I see there are many processes that share the same pgrp as the exact subtree I want to kill. (Additionally, I can't see the setpgrp program listed anywhere in debian stable packages: packages.debian.org/… )
    – STenyaK
    Mar 13 '13 at 7:42






  • 1




    Another use case: renice/ionice on a whole process tree that's eating too many resources, e.g. a large parallel build.
    – Cheetah
    Sep 25 '13 at 4:02














22












22








22


4





I would like to get a list of all the processes that descend (e.g. children, grand-children, etc) from $pid. This is the simplest way I've come up with:



pstree -p $pid | tr "n" " " |sed "s/[^0-9]/ /g" |sed "s/ss*/ /g"


Is there any command, or any simpler way to get the full list of all descendant processes?










share|improve this question















I would like to get a list of all the processes that descend (e.g. children, grand-children, etc) from $pid. This is the simplest way I've come up with:



pstree -p $pid | tr "n" " " |sed "s/[^0-9]/ /g" |sed "s/ss*/ /g"


Is there any command, or any simpler way to get the full list of all descendant processes?







process ps






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 6 '15 at 7:21









perror

1,90441935




1,90441935










asked Mar 12 '13 at 13:58









STenyaK

3253410




3253410












  • Is there a reason you need them all on one line? What are you doing with that output? I have a feeling that this is an xy problem, and you are asking the wrong question.
    – jordanm
    Mar 12 '13 at 17:03










  • I don't care about the format as long as it's clean (i.e. I don't care about 'n' delimited vs. ' ' delimited). Practical use case is: a) a daemonizer script I wrote out of pure masochism (specifically, the "stop" functionality has to deal with whatever tree of processes the daemonized process spawned); and b) a timeout script that will kill whatever the timed-out process managed to create.
    – STenyaK
    Mar 12 '13 at 21:06






  • 2




    @STenyaK Your use cases make me think you're looking for process groups and a negative argument to kill. See unix.stackexchange.com/questions/9480/…, unix.stackexchange.com/questions/50555/…
    – Gilles
    Mar 12 '13 at 21:51










  • @Gilles using ps ax -opid,ppid,pgrp,cmd I see there are many processes that share the same pgrp as the exact subtree I want to kill. (Additionally, I can't see the setpgrp program listed anywhere in debian stable packages: packages.debian.org/… )
    – STenyaK
    Mar 13 '13 at 7:42






  • 1




    Another use case: renice/ionice on a whole process tree that's eating too many resources, e.g. a large parallel build.
    – Cheetah
    Sep 25 '13 at 4:02


















  • Is there a reason you need them all on one line? What are you doing with that output? I have a feeling that this is an xy problem, and you are asking the wrong question.
    – jordanm
    Mar 12 '13 at 17:03










  • I don't care about the format as long as it's clean (i.e. I don't care about 'n' delimited vs. ' ' delimited). Practical use case is: a) a daemonizer script I wrote out of pure masochism (specifically, the "stop" functionality has to deal with whatever tree of processes the daemonized process spawned); and b) a timeout script that will kill whatever the timed-out process managed to create.
    – STenyaK
    Mar 12 '13 at 21:06






  • 2




    @STenyaK Your use cases make me think you're looking for process groups and a negative argument to kill. See unix.stackexchange.com/questions/9480/…, unix.stackexchange.com/questions/50555/…
    – Gilles
    Mar 12 '13 at 21:51










  • @Gilles using ps ax -opid,ppid,pgrp,cmd I see there are many processes that share the same pgrp as the exact subtree I want to kill. (Additionally, I can't see the setpgrp program listed anywhere in debian stable packages: packages.debian.org/… )
    – STenyaK
    Mar 13 '13 at 7:42






  • 1




    Another use case: renice/ionice on a whole process tree that's eating too many resources, e.g. a large parallel build.
    – Cheetah
    Sep 25 '13 at 4:02
















Is there a reason you need them all on one line? What are you doing with that output? I have a feeling that this is an xy problem, and you are asking the wrong question.
– jordanm
Mar 12 '13 at 17:03




Is there a reason you need them all on one line? What are you doing with that output? I have a feeling that this is an xy problem, and you are asking the wrong question.
– jordanm
Mar 12 '13 at 17:03












I don't care about the format as long as it's clean (i.e. I don't care about 'n' delimited vs. ' ' delimited). Practical use case is: a) a daemonizer script I wrote out of pure masochism (specifically, the "stop" functionality has to deal with whatever tree of processes the daemonized process spawned); and b) a timeout script that will kill whatever the timed-out process managed to create.
– STenyaK
Mar 12 '13 at 21:06




I don't care about the format as long as it's clean (i.e. I don't care about 'n' delimited vs. ' ' delimited). Practical use case is: a) a daemonizer script I wrote out of pure masochism (specifically, the "stop" functionality has to deal with whatever tree of processes the daemonized process spawned); and b) a timeout script that will kill whatever the timed-out process managed to create.
– STenyaK
Mar 12 '13 at 21:06




2




2




@STenyaK Your use cases make me think you're looking for process groups and a negative argument to kill. See unix.stackexchange.com/questions/9480/…, unix.stackexchange.com/questions/50555/…
– Gilles
Mar 12 '13 at 21:51




@STenyaK Your use cases make me think you're looking for process groups and a negative argument to kill. See unix.stackexchange.com/questions/9480/…, unix.stackexchange.com/questions/50555/…
– Gilles
Mar 12 '13 at 21:51












@Gilles using ps ax -opid,ppid,pgrp,cmd I see there are many processes that share the same pgrp as the exact subtree I want to kill. (Additionally, I can't see the setpgrp program listed anywhere in debian stable packages: packages.debian.org/… )
– STenyaK
Mar 13 '13 at 7:42




@Gilles using ps ax -opid,ppid,pgrp,cmd I see there are many processes that share the same pgrp as the exact subtree I want to kill. (Additionally, I can't see the setpgrp program listed anywhere in debian stable packages: packages.debian.org/… )
– STenyaK
Mar 13 '13 at 7:42




1




1




Another use case: renice/ionice on a whole process tree that's eating too many resources, e.g. a large parallel build.
– Cheetah
Sep 25 '13 at 4:02




Another use case: renice/ionice on a whole process tree that's eating too many resources, e.g. a large parallel build.
– Cheetah
Sep 25 '13 at 4:02










7 Answers
7






active

oldest

votes


















13














The following is somewhat simpler, and has the added advantage of ignoring numbers in the command names:



pstree -p $pid | grep -o '([0-9]+)' | grep -o '[0-9]+'


Or with Perl:



pstree -p $pid | perl -ne 'print "$1n" while /((d+))/g'


We're looking for numbers within parentheses so that we don't, for example, give 2 as a child process when we run across gif2png(3012). But if the command name contains a parenthesized number, all bets are off. There's only so far text processing can take you.



So I also think that process groups are the way to go. If you'd like to have a process run in its own process group, you can use the 'pgrphack' tool from the Debian package 'daemontools':



pgrphack my_command args


Or you could again turn to Perl:



perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args


The only caveat here is that process groups do not nest, so if some process is creating its own process groups, its subprocesses will no longer be in the group that you created.






share|improve this answer





















  • Child processes are arbitrary and may or may not use process groups themselves (I cannot assume anything). However your answer comes the closest to what seesm to be achievable in Linux, so I'll accept it. Thanks.
    – STenyaK
    Jul 17 '13 at 11:57










  • This was very useful !
    – Michal Gallovic
    Feb 11 '16 at 20:43










  • The pstree pipes will also include the thread ids, i.e. the IDs of the threads a $pid has started.
    – maxschlepzig
    Jan 21 '17 at 9:05










  • You can use single grep: pstree -lp | grep -Po "(?<=()d+(?=))"
    – puchu
    Mar 13 at 21:48





















6














descendent_pids() {
pids=$(pgrep -P $1)
echo $pids
for pid in $pids; do
descendent_pids $pid
done
}





share|improve this answer





















  • It would be only worth noting that this will work on modern shells (bash, zsh, fish, and even ksh 99), but might not work on older shells, e.g. ksh 88
    – grochmal
    Jul 29 '16 at 23:34










  • @grochmal, see my answer below for a traversal solution that does work in ksh-88.
    – maxschlepzig
    Jan 21 '17 at 9:06



















1














The shortest version I have found that also deals correctly with commands like pop3d:



pstree -p $pid | perl -ne 's/((d+))/print " $1"/ge'


It deals wrongly if you have commands that have weird names like: my(23)prog.






share|improve this answer























  • This doesn't work for commands that are running some thread (because pstree prints those IDs, as well).
    – maxschlepzig
    Jan 21 '17 at 9:08



















1














There is also the issue of correctness. Naively parsing the output of pstree is problematic for several reasons:




  • pstree displays PIDs and the ids of threads (names are shown in curly braces)

  • a command name might contain curly braces, numbers in parentheses that make reliable parsing impossible


If you have Python and the psutil package installed you can use this snippet to list all descendant processes:



pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
print(c.pid)"


(The psutil package is e.g. installed as a dependency of the tracer command which is available on Fedora/CentOS.)



Alternatively, you can do an breadth-first traversal of the process tree in a bourne shell:



ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); 
done | tail -n +2 | tr " " "n"


For computing the transitive-closure of a pid, the tail part can be omitted.



Note that the above doesn't use recursion and also runs in ksh-88.



On Linux, one can eliminate the pgrep call and instead read the information from /proc:



ps=2235; while [ "$ps" ]; do echo $ps ; 
ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done
| tr " " "n"' | tail -n +2


This is more efficient because we save one fork/exec for each PID and pgrep does some additional work in each call.






share|improve this answer





























    1














    This Linux version needs /proc and ps only. It's adapted from the last piece of @maxschlepzig's excellent answer. This version reads /proc directly from the shell instead of spawning a sub-process in a loop. It's a bit faster and arguably slightly more elegant, as this thread title requests.



    #!/bin/dash

    # Print all descendant pids of process pid $1
    # adapted from https://unix.stackexchange.com/a/339071

    ps=${1:-1}
    while [ "$ps" ]; do
    echo $ps
    unset ps1 ps2
    for p in $ps; do
    read ps2 < /proc/$p/task/$p/children 2>/dev/null
    ps1="$ps1 $ps2"
    done
    ps=$ps1
    done | tr " " "n" | tail -n +2





    share|improve this answer





























      0














      In each of your two (seemingly very artificial) use cases, why do you want to kill some unfortunate process's sub-processes? How do you know better than a process when its children should live or die? This seems like poor design to me; a process should clean up after itself.



      If you really do know better, then you should be forking these sub-processes, and the 'daemonized process' is apparently too dumb to be trusted to fork(2).



      You should avoid keeping lists of child processes or grovelling through the process tree, eg by putting the child processes in a separate process group as suggested by @Gilles.



      In any case, I suspect that your daemonized process would be better off creating a worker thread pool (which necessarily dies along with its containing process) than a deep tree of sub-sub-sub-processes, which something somewhere then has to clean up.






      share|improve this answer

















      • 2




        Both use cases are used in a continuous integration/testing environment, so they have to deal with the possibility of a bug existing in the child process/es. This bug may manifest itself as inability to properly shutdown themselves or their children, so I need a way to ensure that I can close them all in the worst case.
        – STenyaK
        Jul 17 '13 at 11:55








      • 1




        In that case, I'm with @Gilles and @Jander; process groups are the best way.
        – AnotherSmellyGeek
        Sep 13 '13 at 13:58





















      0














      Here's a pgrep wrapper script which lets you use pgrep and get all descendants at the same time.



      ~/bin/pgrep_wrapper:



      #!/bin/bash

      # the delimiter argument must be the first arg, otherwise it is ignored
      delim=$'n'
      if [ "$1" == "-d" ]; then
      delim=$2
      shift 2
      fi

      pids=
      newpids=$(pgrep "$@")
      status=$?
      if [ $status -ne 0 ]; then
      exit $status
      fi

      while [ "$pids" != "$newpids" ]; do
      pids=$newpids
      newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
      done
      if [ "$delim" != $'n' ]; then
      first=1
      for pid in $pids; do
      if [ $first -ne 1 ]; then
      echo -n "$delim"
      else
      first=0
      fi
      echo -n "$pid"
      done
      else
      echo "$pids"
      fi


      Invoke the same way you'd invoke normal pgrep, such as pgrep_recursive -U $USER java to find all Java processes and sub-processes from the current user.






      share|improve this answer



















      • 1




        Since this is bash, I have a feeling the code used for joining the PIDs with the delimiter could be replaced with setting IFS and using arrays ( "${array[*]}").
        – muru
        Apr 10 '17 at 1:22













      Your Answer








      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "106"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f67668%2felegantly-get-list-of-descendant-processes%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      7 Answers
      7






      active

      oldest

      votes








      7 Answers
      7






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      13














      The following is somewhat simpler, and has the added advantage of ignoring numbers in the command names:



      pstree -p $pid | grep -o '([0-9]+)' | grep -o '[0-9]+'


      Or with Perl:



      pstree -p $pid | perl -ne 'print "$1n" while /((d+))/g'


      We're looking for numbers within parentheses so that we don't, for example, give 2 as a child process when we run across gif2png(3012). But if the command name contains a parenthesized number, all bets are off. There's only so far text processing can take you.



      So I also think that process groups are the way to go. If you'd like to have a process run in its own process group, you can use the 'pgrphack' tool from the Debian package 'daemontools':



      pgrphack my_command args


      Or you could again turn to Perl:



      perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args


      The only caveat here is that process groups do not nest, so if some process is creating its own process groups, its subprocesses will no longer be in the group that you created.






      share|improve this answer





















      • Child processes are arbitrary and may or may not use process groups themselves (I cannot assume anything). However your answer comes the closest to what seesm to be achievable in Linux, so I'll accept it. Thanks.
        – STenyaK
        Jul 17 '13 at 11:57










      • This was very useful !
        – Michal Gallovic
        Feb 11 '16 at 20:43










      • The pstree pipes will also include the thread ids, i.e. the IDs of the threads a $pid has started.
        – maxschlepzig
        Jan 21 '17 at 9:05










      • You can use single grep: pstree -lp | grep -Po "(?<=()d+(?=))"
        – puchu
        Mar 13 at 21:48


















      13














      The following is somewhat simpler, and has the added advantage of ignoring numbers in the command names:



      pstree -p $pid | grep -o '([0-9]+)' | grep -o '[0-9]+'


      Or with Perl:



      pstree -p $pid | perl -ne 'print "$1n" while /((d+))/g'


      We're looking for numbers within parentheses so that we don't, for example, give 2 as a child process when we run across gif2png(3012). But if the command name contains a parenthesized number, all bets are off. There's only so far text processing can take you.



      So I also think that process groups are the way to go. If you'd like to have a process run in its own process group, you can use the 'pgrphack' tool from the Debian package 'daemontools':



      pgrphack my_command args


      Or you could again turn to Perl:



      perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args


      The only caveat here is that process groups do not nest, so if some process is creating its own process groups, its subprocesses will no longer be in the group that you created.






      share|improve this answer





















      • Child processes are arbitrary and may or may not use process groups themselves (I cannot assume anything). However your answer comes the closest to what seesm to be achievable in Linux, so I'll accept it. Thanks.
        – STenyaK
        Jul 17 '13 at 11:57










      • This was very useful !
        – Michal Gallovic
        Feb 11 '16 at 20:43










      • The pstree pipes will also include the thread ids, i.e. the IDs of the threads a $pid has started.
        – maxschlepzig
        Jan 21 '17 at 9:05










      • You can use single grep: pstree -lp | grep -Po "(?<=()d+(?=))"
        – puchu
        Mar 13 at 21:48
















      13












      13








      13






      The following is somewhat simpler, and has the added advantage of ignoring numbers in the command names:



      pstree -p $pid | grep -o '([0-9]+)' | grep -o '[0-9]+'


      Or with Perl:



      pstree -p $pid | perl -ne 'print "$1n" while /((d+))/g'


      We're looking for numbers within parentheses so that we don't, for example, give 2 as a child process when we run across gif2png(3012). But if the command name contains a parenthesized number, all bets are off. There's only so far text processing can take you.



      So I also think that process groups are the way to go. If you'd like to have a process run in its own process group, you can use the 'pgrphack' tool from the Debian package 'daemontools':



      pgrphack my_command args


      Or you could again turn to Perl:



      perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args


      The only caveat here is that process groups do not nest, so if some process is creating its own process groups, its subprocesses will no longer be in the group that you created.






      share|improve this answer












      The following is somewhat simpler, and has the added advantage of ignoring numbers in the command names:



      pstree -p $pid | grep -o '([0-9]+)' | grep -o '[0-9]+'


      Or with Perl:



      pstree -p $pid | perl -ne 'print "$1n" while /((d+))/g'


      We're looking for numbers within parentheses so that we don't, for example, give 2 as a child process when we run across gif2png(3012). But if the command name contains a parenthesized number, all bets are off. There's only so far text processing can take you.



      So I also think that process groups are the way to go. If you'd like to have a process run in its own process group, you can use the 'pgrphack' tool from the Debian package 'daemontools':



      pgrphack my_command args


      Or you could again turn to Perl:



      perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args


      The only caveat here is that process groups do not nest, so if some process is creating its own process groups, its subprocesses will no longer be in the group that you created.







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Jul 14 '13 at 19:01









      Jander

      11.5k43256




      11.5k43256












      • Child processes are arbitrary and may or may not use process groups themselves (I cannot assume anything). However your answer comes the closest to what seesm to be achievable in Linux, so I'll accept it. Thanks.
        – STenyaK
        Jul 17 '13 at 11:57










      • This was very useful !
        – Michal Gallovic
        Feb 11 '16 at 20:43










      • The pstree pipes will also include the thread ids, i.e. the IDs of the threads a $pid has started.
        – maxschlepzig
        Jan 21 '17 at 9:05










      • You can use single grep: pstree -lp | grep -Po "(?<=()d+(?=))"
        – puchu
        Mar 13 at 21:48




















      • Child processes are arbitrary and may or may not use process groups themselves (I cannot assume anything). However your answer comes the closest to what seesm to be achievable in Linux, so I'll accept it. Thanks.
        – STenyaK
        Jul 17 '13 at 11:57










      • This was very useful !
        – Michal Gallovic
        Feb 11 '16 at 20:43










      • The pstree pipes will also include the thread ids, i.e. the IDs of the threads a $pid has started.
        – maxschlepzig
        Jan 21 '17 at 9:05










      • You can use single grep: pstree -lp | grep -Po "(?<=()d+(?=))"
        – puchu
        Mar 13 at 21:48


















      Child processes are arbitrary and may or may not use process groups themselves (I cannot assume anything). However your answer comes the closest to what seesm to be achievable in Linux, so I'll accept it. Thanks.
      – STenyaK
      Jul 17 '13 at 11:57




      Child processes are arbitrary and may or may not use process groups themselves (I cannot assume anything). However your answer comes the closest to what seesm to be achievable in Linux, so I'll accept it. Thanks.
      – STenyaK
      Jul 17 '13 at 11:57












      This was very useful !
      – Michal Gallovic
      Feb 11 '16 at 20:43




      This was very useful !
      – Michal Gallovic
      Feb 11 '16 at 20:43












      The pstree pipes will also include the thread ids, i.e. the IDs of the threads a $pid has started.
      – maxschlepzig
      Jan 21 '17 at 9:05




      The pstree pipes will also include the thread ids, i.e. the IDs of the threads a $pid has started.
      – maxschlepzig
      Jan 21 '17 at 9:05












      You can use single grep: pstree -lp | grep -Po "(?<=()d+(?=))"
      – puchu
      Mar 13 at 21:48






      You can use single grep: pstree -lp | grep -Po "(?<=()d+(?=))"
      – puchu
      Mar 13 at 21:48















      6














      descendent_pids() {
      pids=$(pgrep -P $1)
      echo $pids
      for pid in $pids; do
      descendent_pids $pid
      done
      }





      share|improve this answer





















      • It would be only worth noting that this will work on modern shells (bash, zsh, fish, and even ksh 99), but might not work on older shells, e.g. ksh 88
        – grochmal
        Jul 29 '16 at 23:34










      • @grochmal, see my answer below for a traversal solution that does work in ksh-88.
        – maxschlepzig
        Jan 21 '17 at 9:06
















      6














      descendent_pids() {
      pids=$(pgrep -P $1)
      echo $pids
      for pid in $pids; do
      descendent_pids $pid
      done
      }





      share|improve this answer





















      • It would be only worth noting that this will work on modern shells (bash, zsh, fish, and even ksh 99), but might not work on older shells, e.g. ksh 88
        – grochmal
        Jul 29 '16 at 23:34










      • @grochmal, see my answer below for a traversal solution that does work in ksh-88.
        – maxschlepzig
        Jan 21 '17 at 9:06














      6












      6








      6






      descendent_pids() {
      pids=$(pgrep -P $1)
      echo $pids
      for pid in $pids; do
      descendent_pids $pid
      done
      }





      share|improve this answer












      descendent_pids() {
      pids=$(pgrep -P $1)
      echo $pids
      for pid in $pids; do
      descendent_pids $pid
      done
      }






      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Jul 29 '16 at 23:27









      Russell Davis

      16314




      16314












      • It would be only worth noting that this will work on modern shells (bash, zsh, fish, and even ksh 99), but might not work on older shells, e.g. ksh 88
        – grochmal
        Jul 29 '16 at 23:34










      • @grochmal, see my answer below for a traversal solution that does work in ksh-88.
        – maxschlepzig
        Jan 21 '17 at 9:06


















      • It would be only worth noting that this will work on modern shells (bash, zsh, fish, and even ksh 99), but might not work on older shells, e.g. ksh 88
        – grochmal
        Jul 29 '16 at 23:34










      • @grochmal, see my answer below for a traversal solution that does work in ksh-88.
        – maxschlepzig
        Jan 21 '17 at 9:06
















      It would be only worth noting that this will work on modern shells (bash, zsh, fish, and even ksh 99), but might not work on older shells, e.g. ksh 88
      – grochmal
      Jul 29 '16 at 23:34




      It would be only worth noting that this will work on modern shells (bash, zsh, fish, and even ksh 99), but might not work on older shells, e.g. ksh 88
      – grochmal
      Jul 29 '16 at 23:34












      @grochmal, see my answer below for a traversal solution that does work in ksh-88.
      – maxschlepzig
      Jan 21 '17 at 9:06




      @grochmal, see my answer below for a traversal solution that does work in ksh-88.
      – maxschlepzig
      Jan 21 '17 at 9:06











      1














      The shortest version I have found that also deals correctly with commands like pop3d:



      pstree -p $pid | perl -ne 's/((d+))/print " $1"/ge'


      It deals wrongly if you have commands that have weird names like: my(23)prog.






      share|improve this answer























      • This doesn't work for commands that are running some thread (because pstree prints those IDs, as well).
        – maxschlepzig
        Jan 21 '17 at 9:08
















      1














      The shortest version I have found that also deals correctly with commands like pop3d:



      pstree -p $pid | perl -ne 's/((d+))/print " $1"/ge'


      It deals wrongly if you have commands that have weird names like: my(23)prog.






      share|improve this answer























      • This doesn't work for commands that are running some thread (because pstree prints those IDs, as well).
        – maxschlepzig
        Jan 21 '17 at 9:08














      1












      1








      1






      The shortest version I have found that also deals correctly with commands like pop3d:



      pstree -p $pid | perl -ne 's/((d+))/print " $1"/ge'


      It deals wrongly if you have commands that have weird names like: my(23)prog.






      share|improve this answer














      The shortest version I have found that also deals correctly with commands like pop3d:



      pstree -p $pid | perl -ne 's/((d+))/print " $1"/ge'


      It deals wrongly if you have commands that have weird names like: my(23)prog.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Jul 14 '13 at 21:13

























      answered Jul 14 '13 at 21:05









      Ole Tange

      12k1451105




      12k1451105












      • This doesn't work for commands that are running some thread (because pstree prints those IDs, as well).
        – maxschlepzig
        Jan 21 '17 at 9:08


















      • This doesn't work for commands that are running some thread (because pstree prints those IDs, as well).
        – maxschlepzig
        Jan 21 '17 at 9:08
















      This doesn't work for commands that are running some thread (because pstree prints those IDs, as well).
      – maxschlepzig
      Jan 21 '17 at 9:08




      This doesn't work for commands that are running some thread (because pstree prints those IDs, as well).
      – maxschlepzig
      Jan 21 '17 at 9:08











      1














      There is also the issue of correctness. Naively parsing the output of pstree is problematic for several reasons:




      • pstree displays PIDs and the ids of threads (names are shown in curly braces)

      • a command name might contain curly braces, numbers in parentheses that make reliable parsing impossible


      If you have Python and the psutil package installed you can use this snippet to list all descendant processes:



      pid=2235; python3 -c "import psutil
      for c in psutil.Process($pid).children(True):
      print(c.pid)"


      (The psutil package is e.g. installed as a dependency of the tracer command which is available on Fedora/CentOS.)



      Alternatively, you can do an breadth-first traversal of the process tree in a bourne shell:



      ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); 
      done | tail -n +2 | tr " " "n"


      For computing the transitive-closure of a pid, the tail part can be omitted.



      Note that the above doesn't use recursion and also runs in ksh-88.



      On Linux, one can eliminate the pgrep call and instead read the information from /proc:



      ps=2235; while [ "$ps" ]; do echo $ps ; 
      ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done
      | tr " " "n"' | tail -n +2


      This is more efficient because we save one fork/exec for each PID and pgrep does some additional work in each call.






      share|improve this answer


























        1














        There is also the issue of correctness. Naively parsing the output of pstree is problematic for several reasons:




        • pstree displays PIDs and the ids of threads (names are shown in curly braces)

        • a command name might contain curly braces, numbers in parentheses that make reliable parsing impossible


        If you have Python and the psutil package installed you can use this snippet to list all descendant processes:



        pid=2235; python3 -c "import psutil
        for c in psutil.Process($pid).children(True):
        print(c.pid)"


        (The psutil package is e.g. installed as a dependency of the tracer command which is available on Fedora/CentOS.)



        Alternatively, you can do an breadth-first traversal of the process tree in a bourne shell:



        ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); 
        done | tail -n +2 | tr " " "n"


        For computing the transitive-closure of a pid, the tail part can be omitted.



        Note that the above doesn't use recursion and also runs in ksh-88.



        On Linux, one can eliminate the pgrep call and instead read the information from /proc:



        ps=2235; while [ "$ps" ]; do echo $ps ; 
        ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done
        | tr " " "n"' | tail -n +2


        This is more efficient because we save one fork/exec for each PID and pgrep does some additional work in each call.






        share|improve this answer
























          1












          1








          1






          There is also the issue of correctness. Naively parsing the output of pstree is problematic for several reasons:




          • pstree displays PIDs and the ids of threads (names are shown in curly braces)

          • a command name might contain curly braces, numbers in parentheses that make reliable parsing impossible


          If you have Python and the psutil package installed you can use this snippet to list all descendant processes:



          pid=2235; python3 -c "import psutil
          for c in psutil.Process($pid).children(True):
          print(c.pid)"


          (The psutil package is e.g. installed as a dependency of the tracer command which is available on Fedora/CentOS.)



          Alternatively, you can do an breadth-first traversal of the process tree in a bourne shell:



          ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); 
          done | tail -n +2 | tr " " "n"


          For computing the transitive-closure of a pid, the tail part can be omitted.



          Note that the above doesn't use recursion and also runs in ksh-88.



          On Linux, one can eliminate the pgrep call and instead read the information from /proc:



          ps=2235; while [ "$ps" ]; do echo $ps ; 
          ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done
          | tr " " "n"' | tail -n +2


          This is more efficient because we save one fork/exec for each PID and pgrep does some additional work in each call.






          share|improve this answer












          There is also the issue of correctness. Naively parsing the output of pstree is problematic for several reasons:




          • pstree displays PIDs and the ids of threads (names are shown in curly braces)

          • a command name might contain curly braces, numbers in parentheses that make reliable parsing impossible


          If you have Python and the psutil package installed you can use this snippet to list all descendant processes:



          pid=2235; python3 -c "import psutil
          for c in psutil.Process($pid).children(True):
          print(c.pid)"


          (The psutil package is e.g. installed as a dependency of the tracer command which is available on Fedora/CentOS.)



          Alternatively, you can do an breadth-first traversal of the process tree in a bourne shell:



          ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); 
          done | tail -n +2 | tr " " "n"


          For computing the transitive-closure of a pid, the tail part can be omitted.



          Note that the above doesn't use recursion and also runs in ksh-88.



          On Linux, one can eliminate the pgrep call and instead read the information from /proc:



          ps=2235; while [ "$ps" ]; do echo $ps ; 
          ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done
          | tr " " "n"' | tail -n +2


          This is more efficient because we save one fork/exec for each PID and pgrep does some additional work in each call.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 21 '17 at 9:03









          maxschlepzig

          33.5k32135210




          33.5k32135210























              1














              This Linux version needs /proc and ps only. It's adapted from the last piece of @maxschlepzig's excellent answer. This version reads /proc directly from the shell instead of spawning a sub-process in a loop. It's a bit faster and arguably slightly more elegant, as this thread title requests.



              #!/bin/dash

              # Print all descendant pids of process pid $1
              # adapted from https://unix.stackexchange.com/a/339071

              ps=${1:-1}
              while [ "$ps" ]; do
              echo $ps
              unset ps1 ps2
              for p in $ps; do
              read ps2 < /proc/$p/task/$p/children 2>/dev/null
              ps1="$ps1 $ps2"
              done
              ps=$ps1
              done | tr " " "n" | tail -n +2





              share|improve this answer


























                1














                This Linux version needs /proc and ps only. It's adapted from the last piece of @maxschlepzig's excellent answer. This version reads /proc directly from the shell instead of spawning a sub-process in a loop. It's a bit faster and arguably slightly more elegant, as this thread title requests.



                #!/bin/dash

                # Print all descendant pids of process pid $1
                # adapted from https://unix.stackexchange.com/a/339071

                ps=${1:-1}
                while [ "$ps" ]; do
                echo $ps
                unset ps1 ps2
                for p in $ps; do
                read ps2 < /proc/$p/task/$p/children 2>/dev/null
                ps1="$ps1 $ps2"
                done
                ps=$ps1
                done | tr " " "n" | tail -n +2





                share|improve this answer
























                  1












                  1








                  1






                  This Linux version needs /proc and ps only. It's adapted from the last piece of @maxschlepzig's excellent answer. This version reads /proc directly from the shell instead of spawning a sub-process in a loop. It's a bit faster and arguably slightly more elegant, as this thread title requests.



                  #!/bin/dash

                  # Print all descendant pids of process pid $1
                  # adapted from https://unix.stackexchange.com/a/339071

                  ps=${1:-1}
                  while [ "$ps" ]; do
                  echo $ps
                  unset ps1 ps2
                  for p in $ps; do
                  read ps2 < /proc/$p/task/$p/children 2>/dev/null
                  ps1="$ps1 $ps2"
                  done
                  ps=$ps1
                  done | tr " " "n" | tail -n +2





                  share|improve this answer












                  This Linux version needs /proc and ps only. It's adapted from the last piece of @maxschlepzig's excellent answer. This version reads /proc directly from the shell instead of spawning a sub-process in a loop. It's a bit faster and arguably slightly more elegant, as this thread title requests.



                  #!/bin/dash

                  # Print all descendant pids of process pid $1
                  # adapted from https://unix.stackexchange.com/a/339071

                  ps=${1:-1}
                  while [ "$ps" ]; do
                  echo $ps
                  unset ps1 ps2
                  for p in $ps; do
                  read ps2 < /proc/$p/task/$p/children 2>/dev/null
                  ps1="$ps1 $ps2"
                  done
                  ps=$ps1
                  done | tr " " "n" | tail -n +2






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 18 at 8:18









                  stepse

                  192




                  192























                      0














                      In each of your two (seemingly very artificial) use cases, why do you want to kill some unfortunate process's sub-processes? How do you know better than a process when its children should live or die? This seems like poor design to me; a process should clean up after itself.



                      If you really do know better, then you should be forking these sub-processes, and the 'daemonized process' is apparently too dumb to be trusted to fork(2).



                      You should avoid keeping lists of child processes or grovelling through the process tree, eg by putting the child processes in a separate process group as suggested by @Gilles.



                      In any case, I suspect that your daemonized process would be better off creating a worker thread pool (which necessarily dies along with its containing process) than a deep tree of sub-sub-sub-processes, which something somewhere then has to clean up.






                      share|improve this answer

















                      • 2




                        Both use cases are used in a continuous integration/testing environment, so they have to deal with the possibility of a bug existing in the child process/es. This bug may manifest itself as inability to properly shutdown themselves or their children, so I need a way to ensure that I can close them all in the worst case.
                        – STenyaK
                        Jul 17 '13 at 11:55








                      • 1




                        In that case, I'm with @Gilles and @Jander; process groups are the best way.
                        – AnotherSmellyGeek
                        Sep 13 '13 at 13:58


















                      0














                      In each of your two (seemingly very artificial) use cases, why do you want to kill some unfortunate process's sub-processes? How do you know better than a process when its children should live or die? This seems like poor design to me; a process should clean up after itself.



                      If you really do know better, then you should be forking these sub-processes, and the 'daemonized process' is apparently too dumb to be trusted to fork(2).



                      You should avoid keeping lists of child processes or grovelling through the process tree, eg by putting the child processes in a separate process group as suggested by @Gilles.



                      In any case, I suspect that your daemonized process would be better off creating a worker thread pool (which necessarily dies along with its containing process) than a deep tree of sub-sub-sub-processes, which something somewhere then has to clean up.






                      share|improve this answer

















                      • 2




                        Both use cases are used in a continuous integration/testing environment, so they have to deal with the possibility of a bug existing in the child process/es. This bug may manifest itself as inability to properly shutdown themselves or their children, so I need a way to ensure that I can close them all in the worst case.
                        – STenyaK
                        Jul 17 '13 at 11:55








                      • 1




                        In that case, I'm with @Gilles and @Jander; process groups are the best way.
                        – AnotherSmellyGeek
                        Sep 13 '13 at 13:58
















                      0












                      0








                      0






                      In each of your two (seemingly very artificial) use cases, why do you want to kill some unfortunate process's sub-processes? How do you know better than a process when its children should live or die? This seems like poor design to me; a process should clean up after itself.



                      If you really do know better, then you should be forking these sub-processes, and the 'daemonized process' is apparently too dumb to be trusted to fork(2).



                      You should avoid keeping lists of child processes or grovelling through the process tree, eg by putting the child processes in a separate process group as suggested by @Gilles.



                      In any case, I suspect that your daemonized process would be better off creating a worker thread pool (which necessarily dies along with its containing process) than a deep tree of sub-sub-sub-processes, which something somewhere then has to clean up.






                      share|improve this answer












                      In each of your two (seemingly very artificial) use cases, why do you want to kill some unfortunate process's sub-processes? How do you know better than a process when its children should live or die? This seems like poor design to me; a process should clean up after itself.



                      If you really do know better, then you should be forking these sub-processes, and the 'daemonized process' is apparently too dumb to be trusted to fork(2).



                      You should avoid keeping lists of child processes or grovelling through the process tree, eg by putting the child processes in a separate process group as suggested by @Gilles.



                      In any case, I suspect that your daemonized process would be better off creating a worker thread pool (which necessarily dies along with its containing process) than a deep tree of sub-sub-sub-processes, which something somewhere then has to clean up.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Jul 14 '13 at 15:54









                      AnotherSmellyGeek

                      1785




                      1785








                      • 2




                        Both use cases are used in a continuous integration/testing environment, so they have to deal with the possibility of a bug existing in the child process/es. This bug may manifest itself as inability to properly shutdown themselves or their children, so I need a way to ensure that I can close them all in the worst case.
                        – STenyaK
                        Jul 17 '13 at 11:55








                      • 1




                        In that case, I'm with @Gilles and @Jander; process groups are the best way.
                        – AnotherSmellyGeek
                        Sep 13 '13 at 13:58
















                      • 2




                        Both use cases are used in a continuous integration/testing environment, so they have to deal with the possibility of a bug existing in the child process/es. This bug may manifest itself as inability to properly shutdown themselves or their children, so I need a way to ensure that I can close them all in the worst case.
                        – STenyaK
                        Jul 17 '13 at 11:55








                      • 1




                        In that case, I'm with @Gilles and @Jander; process groups are the best way.
                        – AnotherSmellyGeek
                        Sep 13 '13 at 13:58










                      2




                      2




                      Both use cases are used in a continuous integration/testing environment, so they have to deal with the possibility of a bug existing in the child process/es. This bug may manifest itself as inability to properly shutdown themselves or their children, so I need a way to ensure that I can close them all in the worst case.
                      – STenyaK
                      Jul 17 '13 at 11:55






                      Both use cases are used in a continuous integration/testing environment, so they have to deal with the possibility of a bug existing in the child process/es. This bug may manifest itself as inability to properly shutdown themselves or their children, so I need a way to ensure that I can close them all in the worst case.
                      – STenyaK
                      Jul 17 '13 at 11:55






                      1




                      1




                      In that case, I'm with @Gilles and @Jander; process groups are the best way.
                      – AnotherSmellyGeek
                      Sep 13 '13 at 13:58






                      In that case, I'm with @Gilles and @Jander; process groups are the best way.
                      – AnotherSmellyGeek
                      Sep 13 '13 at 13:58













                      0














                      Here's a pgrep wrapper script which lets you use pgrep and get all descendants at the same time.



                      ~/bin/pgrep_wrapper:



                      #!/bin/bash

                      # the delimiter argument must be the first arg, otherwise it is ignored
                      delim=$'n'
                      if [ "$1" == "-d" ]; then
                      delim=$2
                      shift 2
                      fi

                      pids=
                      newpids=$(pgrep "$@")
                      status=$?
                      if [ $status -ne 0 ]; then
                      exit $status
                      fi

                      while [ "$pids" != "$newpids" ]; do
                      pids=$newpids
                      newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
                      done
                      if [ "$delim" != $'n' ]; then
                      first=1
                      for pid in $pids; do
                      if [ $first -ne 1 ]; then
                      echo -n "$delim"
                      else
                      first=0
                      fi
                      echo -n "$pid"
                      done
                      else
                      echo "$pids"
                      fi


                      Invoke the same way you'd invoke normal pgrep, such as pgrep_recursive -U $USER java to find all Java processes and sub-processes from the current user.






                      share|improve this answer



















                      • 1




                        Since this is bash, I have a feeling the code used for joining the PIDs with the delimiter could be replaced with setting IFS and using arrays ( "${array[*]}").
                        – muru
                        Apr 10 '17 at 1:22


















                      0














                      Here's a pgrep wrapper script which lets you use pgrep and get all descendants at the same time.



                      ~/bin/pgrep_wrapper:



                      #!/bin/bash

                      # the delimiter argument must be the first arg, otherwise it is ignored
                      delim=$'n'
                      if [ "$1" == "-d" ]; then
                      delim=$2
                      shift 2
                      fi

                      pids=
                      newpids=$(pgrep "$@")
                      status=$?
                      if [ $status -ne 0 ]; then
                      exit $status
                      fi

                      while [ "$pids" != "$newpids" ]; do
                      pids=$newpids
                      newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
                      done
                      if [ "$delim" != $'n' ]; then
                      first=1
                      for pid in $pids; do
                      if [ $first -ne 1 ]; then
                      echo -n "$delim"
                      else
                      first=0
                      fi
                      echo -n "$pid"
                      done
                      else
                      echo "$pids"
                      fi


                      Invoke the same way you'd invoke normal pgrep, such as pgrep_recursive -U $USER java to find all Java processes and sub-processes from the current user.






                      share|improve this answer



















                      • 1




                        Since this is bash, I have a feeling the code used for joining the PIDs with the delimiter could be replaced with setting IFS and using arrays ( "${array[*]}").
                        – muru
                        Apr 10 '17 at 1:22
















                      0












                      0








                      0






                      Here's a pgrep wrapper script which lets you use pgrep and get all descendants at the same time.



                      ~/bin/pgrep_wrapper:



                      #!/bin/bash

                      # the delimiter argument must be the first arg, otherwise it is ignored
                      delim=$'n'
                      if [ "$1" == "-d" ]; then
                      delim=$2
                      shift 2
                      fi

                      pids=
                      newpids=$(pgrep "$@")
                      status=$?
                      if [ $status -ne 0 ]; then
                      exit $status
                      fi

                      while [ "$pids" != "$newpids" ]; do
                      pids=$newpids
                      newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
                      done
                      if [ "$delim" != $'n' ]; then
                      first=1
                      for pid in $pids; do
                      if [ $first -ne 1 ]; then
                      echo -n "$delim"
                      else
                      first=0
                      fi
                      echo -n "$pid"
                      done
                      else
                      echo "$pids"
                      fi


                      Invoke the same way you'd invoke normal pgrep, such as pgrep_recursive -U $USER java to find all Java processes and sub-processes from the current user.






                      share|improve this answer














                      Here's a pgrep wrapper script which lets you use pgrep and get all descendants at the same time.



                      ~/bin/pgrep_wrapper:



                      #!/bin/bash

                      # the delimiter argument must be the first arg, otherwise it is ignored
                      delim=$'n'
                      if [ "$1" == "-d" ]; then
                      delim=$2
                      shift 2
                      fi

                      pids=
                      newpids=$(pgrep "$@")
                      status=$?
                      if [ $status -ne 0 ]; then
                      exit $status
                      fi

                      while [ "$pids" != "$newpids" ]; do
                      pids=$newpids
                      newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
                      done
                      if [ "$delim" != $'n' ]; then
                      first=1
                      for pid in $pids; do
                      if [ $first -ne 1 ]; then
                      echo -n "$delim"
                      else
                      first=0
                      fi
                      echo -n "$pid"
                      done
                      else
                      echo "$pids"
                      fi


                      Invoke the same way you'd invoke normal pgrep, such as pgrep_recursive -U $USER java to find all Java processes and sub-processes from the current user.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Apr 10 '17 at 1:22









                      muru

                      1




                      1










                      answered Apr 10 '17 at 1:01









                      zeroimpl

                      1011




                      1011








                      • 1




                        Since this is bash, I have a feeling the code used for joining the PIDs with the delimiter could be replaced with setting IFS and using arrays ( "${array[*]}").
                        – muru
                        Apr 10 '17 at 1:22
















                      • 1




                        Since this is bash, I have a feeling the code used for joining the PIDs with the delimiter could be replaced with setting IFS and using arrays ( "${array[*]}").
                        – muru
                        Apr 10 '17 at 1:22










                      1




                      1




                      Since this is bash, I have a feeling the code used for joining the PIDs with the delimiter could be replaced with setting IFS and using arrays ( "${array[*]}").
                      – muru
                      Apr 10 '17 at 1:22






                      Since this is bash, I have a feeling the code used for joining the PIDs with the delimiter could be replaced with setting IFS and using arrays ( "${array[*]}").
                      – muru
                      Apr 10 '17 at 1:22




















                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Unix & Linux Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f67668%2felegantly-get-list-of-descendant-processes%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Morgemoulin

                      Scott Moir

                      Souastre