A process[1] is a running program. Everything you launch from the shell is a process. Understanding how to manage processes — run them in the background, stop them, kill them, and chain them conditionally — is not optional knowledge. It will come up every day.
Background and foreground
./long_render &The & at the end of a command runs it in the background. The shell
prints the job number and PID, then returns the prompt immediately.
The process keeps running.
[1] 48291 jobs # list background jobs for this shell session
fg # bring the most recent background job to the foreground
fg %1 # bring job number 1 to the foregroundCtrl-Z suspends the foreground process (pauses it) and puts it in
the background. Then fg to resume it, or bg to let it keep running
in the background.
./render # starts in foreground
^Z # Ctrl-Z: suspend[1]+ Stopped ./renderbg # resume in backgroundInterrupting and killing
Ctrl-C sends SIGINT (signal 2) to the foreground process. Most
programs treat this as "stop what you are doing and exit cleanly." It
is the polite way to stop a process.
kill 48291 # send SIGTERM (15) — ask the process to exit
kill -9 48291 # send SIGKILL — force terminate, immediately
kill -SIGINT 48291 # send SIGINT by namekill sends a signal to a process by PID. SIGTERM (the default)
asks the process to terminate; the process can catch it and clean up.
SIGKILL cannot be caught or ignored — the kernel terminates the
process immediately. Use -9 only when the process is genuinely
unresponsive.
Finding processes
ps aux # all running processes
ps aux | grep 'render' # find a specific process by name
pgrep render # print PIDs of processes named "render"
pkill render # kill all processes named "render"ps aux produces a lot of output. Pipe it through grep to find
what you are looking for.
Exit codes
Every process exits with a number. 0 means success. Anything else
means failure. The shell stores the exit code of the last command in
$?:
ls /nonexistent
echo $? # prints 2 (or similar non-zero)
ls /tmp
echo $? # prints 0Conditional chaining
Exit codes make && and || useful:
gcc main.c -o main && ./main&& runs the right side only if the left side exited with 0. This
compiles and runs only if compilation succeeded. It is the shell
equivalent of "if this worked, then do that."
./build.sh || echo "build failed"|| runs the right side only if the left side failed (non-zero
exit). Use it for fallbacks and error reporting in scripts.
mkdir output && cp *.c output/ && echo "done" || echo "failed"Chain as many commands as you need. If any one fails, the rest do not
run and || catches the failure. If everything succeeds, echo "done"
exits with 0 and the || leg is skipped.
In c05/03 you will build the internals of | in C.
That chapter is built on fork, exec, dup2, and waitpid — the
system calls that create processes, replace them with a new program,
rewire their file descriptors, and wait for them to finish. Exit codes
are not a shell convention in that chapter; they are the return value
of waitpid. SIGINT is not a keyboard shortcut; it is a signal your
shell sends to a process group. Everything on this page is the
vocabulary that makes that chapter readable.