I'm trying to build a process container. The container will trigger other programs. For example - a bash script that launches running background tasks with '&' usage.

The important feature I'm after is this: when I kill the container, everything that has been spawned under it should be killed. Not just direct children, but their descendants too.

When I started this project, I mistakenly believed that when you killed a process its children were automatically killed too. I've sought advice from people who had the same incorrect idea. While it's possible to catch a signal and pass the kill on to children, that's not what I'm looking for here.

I believe what I want to be achievable, because when you close an xterm, anything that was running within it is killed unless it was nohup'd. This includes orphaned processes. That's what I'm looking to recreate.

I have an idea that what I'm loooking for involves unix sessions.

If there was a reliable way to identify all the descendants of a process, it would be useful to be able to send them arbitrary signals, too. e.g. SIGUSR1.

  • Well, killing the parent process sends SIGHUP to it's direct children processes. The default handler of hang up signal aborts process execution, so the default route is to kill all the descendants. Read more on processes and process groups.
    – alex
    Commented Jun 11, 2011 at 13:27
  • Closing the xterm kills everything spawned in the xterm because the TTY is destroyed. If you can come up with a way to create a tty which child processes can use, you can then destroy the TTY and accomplish the same thing. Any process which didnt close that TTY (nohup & friends) will get a SIGHUP.
    – phemmer
    Commented Jun 12, 2011 at 10:34
  • @alex Is that true if the children processes are backgrounded? Commented Jan 1, 2023 at 23:31

9 Answers 9


If you send a signal to a process, that process gets killed. I wonder how the rumor that killing a process also kills other processes got started, it seems particularly counter-intuitive.

There are, however, ways to kill more than one process. But you won't be sending a signal to one process. You can kill a whole process group by sending a signal to -1234 where 1234 is the PGID (process group ID), which is the PID of the process group leader. When you run a pipeline, the whole pipeline starts out as a process group (the applications may change this by calling setpgid or setpgrp).

When you start processes in the background (foo &), they are in their own process group. Process groups are used to manage access to the terminal; normally only the foreground process group has access to the terminal. The background jobs remain in the same session, but there's no facility to kill a whole session or even to enumerate the process groups or processes in a session, so that doesn't help much.

When you close a terminal, the kernel sends the signal SIGHUP to all processes that have it as their controlling terminal. These processes form a session, but not all sessions have a controlling terminal. For your project, one possibility is therefore to start all the processes in their own terminal, created by script, screen, etc. Kill the terminal emulator process to kill the contained processes (assuming they haven't seceded with setsid).

You can provide more isolation by running the processes as their own user, who doesn't do anything else. Then it's easy to kill all the processes: run kill (the system call or the utility) as that user and use -1 as the PID argument to kill, meaning “all of that user's processes”.

You can provide even more isolation, but with considerably more setup by running the contained processes in an actual container.

  • 1
    If you program your own processes, then you can use something such as: prctl(PR_SET_PDEATHSIG, SIGHUP);, more info: man7.org/linux/man-pages/man2/prctl.2.html Commented Jul 19, 2016 at 19:33
  • Gilles, you mention this - "When you close a terminal, the kernel sends the signal SIGHUP to all processes that have it as their controlling terminal". From this I'm surmising the terminal sends SIGHUP to the session leader (shell) who forwards it on to all process groups within the session. Which of the two would be right?
    – iruvar
    Commented Oct 24, 2018 at 4:35

A reliable way to identiry all the descendants of a process is to use the command pstree <pid> where pid is your parent process id.

Read the man page on pstree here.

To signal all members of a process group: killpg(<pgrp>, <sig>);
where pgrp is the process group number and sig is the signal.

To wait for children in a specified process group: waitpid(-<pgrp>, &status, ...);

An alternative to what you're doing is to run your process container in a new bash shell. Create the new bash shell with the command bash and then run your processes. When you want all processes to be ended, exit the shell with the command exit.

  • I think killpg will allow me to do what I need to do. Thanks. Commented Jun 12, 2011 at 12:24

Within the parent script trap the kill signal and have it kill all the children. For example,

# kill the parent and children together
trap "kill 0" EXIT
# create all the children
for n in $(seq 1 100)
    ( echo "begin $n"; sleep 60; echo "end $n" ) &
# wait for the children to complete

You could use this kind of shell script:

set -m; (
# start the processes in this container:
) & set +m; pid=$!
# terminate the container:
kill -- -"$pid"

The trick is to enable job control for the container subshell so that the processes executed there get common unique process group ID, which you can use by the given kill command to kill all the processes.

  • 1
    This was the only answer that worked for me, on OSX without gnu ps. Also other answers kill kill 0 killed my parent script, which I wanted to avoid because I wanted to do processing after the children exited. Commented Jun 15, 2020 at 23:22
  • Note that it might be unnecessary to switch the m option, if it is already set in the beginning. If you use dash ( and you call the shell with -m, then set -m will change process group of the shell match with the caller's process group.
    – jarno
    Commented Oct 25, 2020 at 13:08
  • @BlueDrink9 Does my other answer work for you?
    – jarno
    Commented Oct 25, 2020 at 14:31


unshare -fp --kill-child -- yourprogram

If you kill unshare, all child processes (that yourprogram may have spawned) will be killed.

This is now possible with util-linux 2.32; I implemented this upstream. It requires either user namespaces (kernel config option CONFIG_USER_NS=y) or root privileges. See also here.


rkill command from pslist package sends given signal (or SIGTERM by default) to specified process and all its descendants:

rkill [-SIG] pid/name...

Another option for killing all descendants of the shell: jobs -p | xargs -n 1 pkill -P


At least if you use Bash (5.0.17), you could use the following:

    #!/bin/bash -m
    set +m
    trap 'kill -- -$$' EXIT
    process1 &
    process2 &

There are some problems if you send USR1 signal to the process group, though.

If you use dash (, set +m will switch process group to match the process group of the caller, thus killing this process (group) would kill the caller, too.


pgrep -P ppid: Restrict matches to processes with a parent process ID in the comma-separated list ppid.

# ZSH code
function ps-children() {
    pgrep -P "$1"
function ps-grandchildren() {
  local children=( $(ps-children "$1") ) pid

  for pid in $children[@]
    "$0" "$pid"

  print -r -- "${(F)children}"
function kill-withchildren() {
    setopt localoptions re_match_pcre
    local sig=2
    if [[ "$1" =~ '-\d+' ]] ; then
    local pids=("$@") pid

    for pid in "$pids[@]" ; do
        local children=("${(@f)$(ps-grandchildren "$pid")}")
        kill -$sig "$pid" "$children[@]"
  • This is odd, you call the script recursively, but there are only functions in the script. Also your for loops do not work in Bash. What does "${(F)children}" mean?
    – jarno
    Commented Sep 5, 2020 at 22:50
  • 1
    @jarno $children[@] will eventually become empty, and the recursion will terminate. The code is in zsh; "${(F)children}" joins the array using \n.
    – HappyFace
    Commented Sep 6, 2020 at 3:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .