You are on page 1of 10

A process is any running program with its own address space.

A job is a concept used by the shell - any program you interactively start that doesn't detach (ie,
not a daemon) is a job. If you're running an interactive program, you can press CtrlZ to suspend it.
Then you can start it back in the foreground (using fg) or in the background (using bg).

While the program is suspended or running in the background, you can start another program -
you would then have two jobs running. You can also start a program running in the background by
appending an "&" like this: program &. That program would become a background job. To list all
the jobs you are running, you can use jobs.

UNIX has separate concepts "process", "process group", and "session".


Each shell you get at login becomes the leader of its own new session and process group, and sets
the controlling process group of the terminal to itself.

The shell creates a process group within the current session for each "job" it launches, and places
each process it starts into the appropriate process group. For example, ls | head is a pipeline of two
processes, which the shell considers a single job, and will belong to a single, new process group.

A process is a (collection of) thread of execution and other context, such as address space and file
descriptor table. A process may start other processes; these new processes will belong to the same
process group as the parent unless other action is taken. Each process may also have a "controlling
terminal", which starts off the same as its parent.

The shell has the concept of "foreground" jobs and "background" jobs. Foreground jobs are proc
ess groups with control of the terminal, and background jobs are process groups without control of
the terminal.

Each terminal has a foreground process group. When bringing a job to the foreground, the shell
sets it as the terminal's foreground process group; when putting a job to the background, the shell
sets the terminal's foreground process group to another process group or itself.

Processes may read from and write to their controlling terminal if they are in the foreground
process group. Otherwise they receive SIGTTIN and SIGTTOU signals on attempts to read from
and write to the terminal respectively. By default these signals suspend the process, although most
shells mask SIGTTOU so that a background job can write to the terminal uninterrupted.

Above definitions are very technical but maybe the op wanted a more day to day clarification. I
think that a job is a scheduled process. When we deal with processes in general there is not
necessarily the notion of schedule, but when we use the word "job" we always mean that it is
scheduled, or repetitive like a loop, it's like a worker.

It is possible to reattach the filedescriptors to a different file by attaching the program in a debug
ger (i.e. using ptrace) and making it call open, dup and close. There are a few tools that do this;
this is a tricky process, and sometimes they will crash the process instead.
Using tmux, you could detach the session, and re-attach it in another terminal. When you detached
from previous session, you can safely close the terminal; later use tmux attach to get back to the
session, even if you logged out.

There's also a small utility called retty that lets you reattach running programs to another terminal.

A process group is a unix kernel concept. It doesn't come up very often. You can send a signal to
all the processes in a group, by calling the kill system call or utility with a negative argument.

When a process is created (with fork), it remains in the same process group as its parent. A process
can move into another group by calling setpgid or setpgrp. This is normally performed by the shell
when it starts an external process, before it executes execve to load the external program.

The main use for process groups is that when you press Ctrl+C, Ctrl+Z or Ctrl+\ to kill or suspend
programs in a terminal, the terminal sends a signal to a whole process group, the foreground
process group. The details are fairly complex and mostly of interest to shell or kernel implement
ers; the General Terminal Interface chapter of the POSIX standard is a good presentation (you do
need some unix programming background).

Jobs are an internal concept to the shell. In the simple cases, each job in a shell corresponds to a
process group in the kernel.

Keep reading everywhere that this command should terminate all child processes of the parent
process:
kill -- -$$

Using a negative ID with the kill command references a PGID and from the examples I have seen
it appears the PGID of child processes should be the PID of the parent but its not the case on my
system.

On my system the PGID of the child is the same as the PGID of the parent script which turns out
to be bash.

What's going on here? Were the examples wrong or is my system set up differently?
What I need to achieve is to terminate child processes without terminating the parent so I don't
want to send a kill signal to the PGID the parent is in.

When a process is forked, it inherits its PGID from its parent. The PGID changes when a process
becomes a process group leader, then its PGID is copied from its PID. From then on, the new child
processes it spawns, and their descendants, inherit that PGID (unless they start new process groups
of their own).
In a shell with job control, such as most interactive shells, each job is put in its own process group.
If you run a shell script, the shell process running the script will be the group leader, and the PGID
will equal its PID.

In a shell without job control, such as most shells used to run scripts, commands are run in the
shell's process group.

The syntax kill -- -N kills all the processes in the group with PGID = N. You can't use it with an
arbitrary PID, only the PID of a process group leader, since that's the PGID. This is essentially
how the shell's

kill %jobid
syntax works -- it internally translates %jobid to the PGID of the job and sends the signal to that
PGID.

There's no simple way to run a script in its own process group from another shell script.

A shell with job control starts a new process group for each job. But a shell without job control
does not start a new process group for each job, it runs them in its own process group.

With job control, each child gets its own PGID. Without job control, they inherit the PGID of the
parent. But the parent might have inherited its PGID from its parent, if it's not a process group
leader.

The job id is mostly just a shell construct. There is support in the kernel in the form of the signals
that are involved in job control, and the way in which the kernel knows exactly which processes to
send the job control signals to.

Strictly speaking, the answer is that the job id is purely a shell creation. It exists because a pipeline
(or, rarely, another shell grouped construct) may consist of multiple processes that should be
controlled as a unit.

The shell starts all processes by first doing a fork(2) and then doing an execve(2). The only
difference with & is that the shell does not do a wait(2) (or a related variant) and so the program
can continue "in the background". There is actually little distinction in Unix between foreground
and background.

The process group is an association defined by shells so that the kernel knows about a single
"foreground" process that handles a set of various "background" processes. This is mainly import
ant so that the background processes will generate a signal should they decide to suddenly read
from a terminal. (Such terminal probably being connected to standard input.) This will cause the
"job" to generate a signal and the shell will prompt the user to do something.
Try (sleep 5; read x)& and after 6 seconds type a return or something so that the shell wakes up.
That's when you see something like...
[1]+ Stopped ( sleep 5; read x )
...and you then type fg to pull it into the foreground.

Originally, Unix had pipelines, and it had &, but there was no way to move a command or pipeline
between foreground and background and no way to help a background process that suddenly
decided to read standard input.

Job control and the kernel support for it were added by Bill Joy and others in early versions of
BSD and csh(1). These were picked up line-for-line by commercial Unix and in cloned for the
work-alike Linux kernel.

Regarding the questions about process groups and ps(1)... In order to support job control in shells,
the kernel process state includes a process group ID and a session ID. A process group and a job
are the same thing, but a job number is just a handle the shell makes up. A process is a session
leader if the session ID is the same as the pid, and a process is a process group leader if the pgid is
the same as the pid. I believe something a bit more subtle is happening with the + that ps(1) prints.
Each terminal knows what its foreground process group is, so I believe a process gets a + if pid ==
pgid && (pgid is the foreground pg for its controlling terminal).

In summary, the kernel keeps several items of state: pid, pgid, sid, and a process may have a
controlling terminal and a terminal may have a foreground pgid. These credentials are mostly
intended to support job control but are also used to revoke access to a terminal when a user log
out.

A process group is a collection of related processes which can all be signalled at once.
A session is a collection of process groups, which are either attached to a single terminal device
(known as the controlling terminal) or not attached to any terminal.

Sessions are used for job control: one of the process groups in the session is the foreground
process group, and can be sent signals by terminal control characters. You can think of a session
with a controlling terminal as corresponding to a "login" on that terminal. (Daemons normally
disassociate themselves from any controlling terminal by creating a new session without one.)

e.g. if you run some_app from the shell, the shell creates a new process group for it, and makes
that the foreground process group of the session. (some_app might create some child processes; by
default they will be part of the same process group.) If you then press ^Z, some_app's process
group is signalled to stop it; and the shell's process group is switched to be the foreground process
group again. Then e.g.bg %1 would start some_app's process group again, but keep it running in
the background.

Job control shells manipulate sessions or process groups all the time. You can send the same signal
to all the processes in a process group with a single call to the POSIX kill() function.
When a login shell exits, e.g., a SIGHUP signal is sent to all programs in its process group.
When you manipulate programs into foreground or background, you are using process groups.

There are also controlling terminals to worry about; signals generated by a controlling terminal
can be sent to all programs in a process group.

Moving a job from the background to the foreground, or from suspended to the foreground,
involves changing the terminal's pgrp, not the job's or shell's pgrp.

$sleep 3000 &


$sleep 2000 &
$ps xao pid,ppid,pgid,sid,tty,comm | grep tty
PID PPID PGID SID TTY COMMAND
1153 1135 1153 1153 tty1 bash
1173 1153 1173 1153 tty1 sleep
1189 1153 1189 1153 tty1 sleep
1219 1153 1219 1153 tty1 ps
1220 1153 1219 1153 tty1 grep

The shell has different PGID from 3 pipelines of programs as the output above.

Basically, the kernel mapped the tty to an PGID. Processes that have that PGID is in foreground,
meanwhile other processes with different PGID are in the background. Of course they have the
same SID and PPID as the output above.

You shouldn't, since neither of the sources you quote claim that the shell's PGID is equal to the
foreground job PGID.

The shell's PGID does not change. In a normal scenario with an interactive shell running in a
terminal, the shell is in its own process group and the shell's PGID is equal to the shell's PID.

Each process has a PGID. The terminal has an associated foreground process group ID. The
foreground process group is, by definition, the process group with that PGID.

Note that if the terminal is provided by a terminal emulator, there is no relation between any of
this and the PID of the terminal emulator process. This should be obvious if you think of hardware
terminals, provided entirely by the kernel: there's no terminal emulator process in that situation.

The terminal's associated PGID can be set by the tcsetpgrp function, which is called by the shell
when it starts an external program in the foreground, or moves a job into the foreground with fg.

The idea comes from csh from Bill Joy from around 1979 1980. The related kernel support was
added by Bill Joy to enable this feature at all.
Because the original csh was written with vfork() support at that time already, it is hard to under
stand the code from csh as vfork() requires to revert effects in the parent from actions in the child
that are a result of the shared memory between parent and child in vfork().

If you like to understand a working implementation, I recommend to read the Bourne Shell source
code. The shell when it starts checks whether it is a process group leader or not and if needed
makes itself a process group leader.

Of course, the shell keeps this id during it's lifetime unless it was not a process group leader at
startup and it likes to suspend itself. Note that this is not fully supported in bash...

To make started jobs managable, each job is run in a separate new and own process group id.

exec replaces the shell with another program. Using exec in a simple background job isn't useful:
exec myprogram; more stuff replaces the shell with myprogram and so doesn't run more stuff,
unlike myprogram; more stuff which runs more stuff when myprogram terminates; but exec
myprogram & more stuff starts myprogram in the background and then runs more stuff, just like
myprogram & more stuff.

nohup runs the specificed program with the SIGHUP signal ignored. When a terminal is closed,
the kernel sends SIGHUP to the controlling process in that terminal (i.e. the shell). The shell in
turn sends SIGHUP to all the jobs running in the background. Running a job with nohup prevents
it from being killed in this way if the terminal dies (which happens e.g. if you were logged in
remotely and the connection drops, or if you close your terminal emulator).

nohup also redirects the program's output to the file nohup.out. This avoids the program dying
because it isn't able to write to its output or error output. Note that nohup doesn't redirect the input.
To fully disconnect a program from the terminal where you launched it, use
nohup myprogram </dev/null >myprogram.log 2>&1 &

By testing I saw that when I ran exec firefox and then closed firefox, it also closed my shell. I
understood what nohup does but I don't understand what you mean when you say exec replaces
the shell with the <program> ?

After you run exec firefox, the shell is no longer running: it has been replaced by firefox. You can
think of exec as combining exiting a program and starting a new one, but keeping the same
process ID. The terminal keeps running because nothing told it to stop. When you later exit
Firefox, the firefox process terminates. The terminal notices that its child process has exited and so
it exits in turn.

exec & => executes a process as a background process so you may continue using the same
terminal for other jobs.
nohup => avoids all SIGHUP(terminate signal) and continues execution even if you terminal is
closed.

exec process dies when a SIGHUP is received, but nohup process continues.

This answer appears to be correct. As other answers above say, normally exec replaces the running
process, but that doesn't seem to happen when you use & to background the exec'd command.
Neither in bash nor zsh

You can't compare nohup with exec. When you run an executable with nohup, the process won't
be killed when you logout (ssh session); usually nohup is used with nice to run processes on a
lower priority. The HUP signal is, by convention, the way a terminal warns dependent processes of
logout.

The shell built in command exec <command> replaces the shell with <command>, no new
process, no new PID is created. After completion of <command> normally your terminal will
close. By running it in the background first a subshell is created, which then similarly is
immediately replaced by <command>.

The nohup <command> command will run <command> but immume to hangups (kill -s 1) so it
will not be terminated when the shell, the terminal from which it was started is, is closed. By
running it in the background first a subshell is created and the command runs in the background,
returning you to the prompt.

In scripting the immediate effect is more or less the same though, <command> is started by your
script and the script will continue without waiting for <command> to start, to send output or to
complete.

ps xao pid,ppid,pgid,sid,command | grep "PGID\|23890"


PID PPID PGID SID COMMAND
23890 11892 23890 23890 bash
24714 23890 24714 23890 ./a.out
It makes sense to me that the parent process of my a.out is bash. At first I thought "bash's pid
matches its pgid - that must be because it's the process group leader. Maybe that makes sense
because bash is kind of the "first thing" that got run, from which I ran my process." But that reas
oning doesn't make sense because a.out's pgid also matches its own pid.

Why doesn't a.out's pgid equal bash's pgid? That's what I would have expected from my under
standing of the quote.

There is no conflict; a process will by default be in a unique process group which is the process
group of its parent:
$ cat pg.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
fork();
printf("pid=%d pgid=%d\n", getpid(), getpgrp());
}
$ make pg
cc pg.c -o pg
$ ./pg
pid=12495 pgid=12495
pid=12496 pgid=12495
$
The fork splits our process into parent (12495) and child (12496), and the child belongs to the
unique process group of the parent (12495). bash departs from this because it issues additional
system calls:
$ echo $$
12366
$
And then in another terminal we run:
$ strace -f -o blah -p 12366
And then back in the first terminal:
$ ./pg
pid=12676 pgid=12676
pid=12677 pgid=12676
$
And then we control+c the strace, and inspect the system calls:
$ egrep 'exec|pgid' blah
12366 setpgid(12676, 12676) =0
12676 setpgid(12676, 12676 <unfinished ...>
12676 <... setpgid resumed> ) =0
12676 execve("./pg", ["./pg"], [/* 23 vars */]) = 0
12676 write(1, "pid=12676 pgid=12676\n", 21 <unfinished ...>
12677 write(1, "pid=12677 pgid=12676\n", 21 <unfinished ...>
bash has used the setpgid call to set the process group, thus placing our pg process into process
group unrelated to that of the shell. (setsid(2) would be another way to tweak the process group, if
you're hunting for system calls.)

The strace tells us bash (pid 12366) leads to creation (I guess forking) of child process (pid
12676). Then bash calls setpgid to set the pgid of the child process (12676) to 12676. But what's
with the second call to setpgid(12676, 12676) that seems to be performed by process 12676? Then
lastly, bash execves the program to kick off the process.
And I guess the explicit call to setpgid would be the reason why pg's pgid doesn't match bash's
pgid. As opposed to the parent/child processes from the pg executable that demonstrate the
"expected" behavior because there is no explicit call to setpgid() (?)

There's a fork (clone, actually) not shown where bash splits into 12366 and 12676. The call comp
lications aside, it's mostly to show that bash does not follow the expected behavior because it
makes an extra system call.

bash puts the child into a new process group to implement job control. Each job has to be a
separate process group from the shell so it can be moved from foreground to background.

In the following session, bash starts two distinct pipelines, but they share the same pgid. When the
ls pipeline is removed (so the distinct pipelines are not invoked in a subshell), the two pipes get
distinct process groups. What gives? In particular, is it correct behavior for the non-interactive
shell to put distinct pipelines in the same process group? Or am I misinterpreting something?

bash-3.2$ cat print-pgid


#!/bin/sh
echo $$ starting in $(ps -o pgid= $$) >&2
bash-3.2$ ls | for i in a b; do ./print-pgid | ./print-pgid & done
bash-3.2$ 67396 starting in 67393
67395 starting in 67393
67397 starting in 67393
67398 starting in 67393

bash-3.2$ for i in a b; do ./print-pgid | ./print-pgid & done


[1] 67404
[2] 67406
bash-3.2$ 67404 starting in 67403
67403 starting in 67403
67405 starting in 67405
67406 starting in 67405
[1]- Done ./print-pgid | ./print-pgid
[2]+ Done ./print-pgid | ./print-pgid
bash-3.2$

In the second example, the for loop is executed in the current, interactive shell, which has job
control enabled. Job control requires each job to be in its own process group.
But when you pipe from ls, the for loop is executed in a subshell. Because it's not an interactive
shell, there's no job control, so there's no need to put each pipeline in its own process group. So
that entire subshell is just a single process group.
The reason you can't see it in the "jobs" command or use "fg" to bring it to the foreground is
because these commands are actually built-in to the shell. They don't technically detach the
processes from the terminal you're connected with, so when you exit the shell they should exit as
well (you should get a warning when you attempt to exit).

Sometimes you need to use 'sudo' to run the command. syntax: "sudo reptyr –s PID " and it brings
my python process from other terminal active in the current one.

You might also like