Skip to main content
A shell script is a file containing shell commands and programming constructs that automate tasks. When a new process starts, the kernel assigns a unique process ID (PID) that you can use to inspect, control, or terminate that process. How many PIDs are created while a shell script runs? Think of the parent shell as a chef in a kitchen; each command the chef issues is a worker (a process) with its own unique identifier (PID). The parent shell spawns child processes for the commands it runs, and those children can in turn spawn their own children. In an interactive terminal session the parent shell is the session’s shell process. Commands you type spawn child processes; each child has its own PID and a PPID (parent PID) pointing back to the shell that launched it.
A dark presentation slide titled "PID" showing "Parent Shell" on the left pointing to three colorful fingerprint-style icons labeled "Process ID." One of those process icons is connected by a dotted line to a dashed box labeled "Child Processes."
Each instruction the chef gives consumes a worker (a process). Each worker receives a unique identifier—just like each process gets a PID. The chef (the parent shell) can check, stop, or restart any worker; likewise, you can inspect and control processes from the command line. Terminal sessions are attached to a TTY (teletypewriter). The session leader (the parent shell process) manages that TTY. Child processes spawned by the shell normally remain associated with the same TTY and appear in process listings with that TTY name.
A dark presentation slide titled "PID" showing a diagram with "Parent Shell" on the left connected by a dotted line to a terminal icon on the right. The connection is labeled "TTY" with a lightbulb icon above it.
Quick commands to inspect your terminal and shell processes:
# list processes and search for bash
$ ps -ef | grep bash
501 29898 27796 0 11:00PM ttys007 0:00.01 bash
501 29928 29898 0 11:00PM ttys007 0:00.00 grep bash

# show the TTY for your current terminal
$ tty
/dev/ttys007
Each terminal tab or window typically has a different TTY. For example, open a second tab and you’ll likely see a different TTY and another bash process:
# Tab 1
$ tty
/dev/ttys000

$ ps -ef | grep bash
501 87852 87851 0 8:32PM ttys000 0:00.76 -bash

# Tab 2
$ tty
/dev/ttys001

$ ps -ef | grep bash
501 8561 8560 0 12:36AM ttys001 0:00.04 -bash
Observe PID chains with a simple script that sleeps so we can watch spawned processes:
# script.sh
#!/bin/bash
sleep 180
Make it executable and run in the foreground:
$ chmod +x script.sh
$ ./script.sh
While the script runs in the foreground, the launching shell is occupied. Inspecting processes shows the script has its own PID, and the PPID points back to the shell that started it:
$ ps -ef | grep script.sh
501 8689 87852 0 12:36AM ttys000 0:00.00 /bin/bash ./script.sh
501 87852 87851 0 8:32PM ttys000 0:00.77 -bash
Within the script the sleep command itself spawns a child process:
$ ps -ef | grep sleep
501 8690 8689 0 12:36AM ttys000 0:00.00 sleep 180
This shows the parent-child chain:
  • shell (parent) → script (child) → sleep (grandchild)
To run the script without blocking the terminal, send it to the background with &:
$ ./script.sh &
[1] 8862
A background job has a PID and remains associated with the launching shell’s TTY. If you close the terminal, the background job will typically receive SIGHUP and terminate. To keep a process running after the terminal closes, detach it from the session using nohup (or alternatives like setsid or disown). nohup prevents SIGHUP from terminating the process and redirects output to nohup.out by default:
$ nohup ./script.sh & 
[1] 9028
appending output to nohup.out

$ ps -ef | grep script.sh
501 9028 1      0 12:39AM ??      0:00.00 /bin/bash ./script.sh
Notice the PPID may change (commonly to 1) and the TTY can become ”??”, indicating the process is no longer attached to the terminal.
Use nohup to detach a process from its terminal so it survives when the terminal closes. Alternatives include setsid (start a new session) or using job control (run, then disown) for interactive shells.
Not all commands create new processes. Shell builtins (for example, cd, export, read) execute inside the current shell and do not create separate PIDs when invoked directly. Many builtins also exist as external binaries; invoking the external binary (for example /usr/bin/command) will create a new process.
A dark UI slide titled "PID" showing a cyan code icon and the label "Built-in Commands" on the left with a chevron arrow to the right. A faint "© Copyright KodeKloud" appears in the bottom-left.
Process execution methods at a glance:
Execution methodWhen it creates a new PIDExample
Run by name (PATH)Creates a new process for the external binary found in PATHls, cat
Run by absolute pathCreates a new process for the specified binary/usr/bin/cat file.txt
Run from current directoryCreates a new process (explicit path)./script.sh
Shell builtinRuns inside the shell, no new PIDcd, export, read
Example showing binary by name vs absolute path:
$ cat file.txt
Hello World!

$ /usr/bin/cat file.txt
Hello World!
To inspect running processes, use ps and top (or htop). ps -ef gives full details (user, PID, PPID, TTY, time, and command). Note that ps output and options differ across Unix-like systems (Linux, macOS, BSD).
$ ps -ef | grep bash
501 87852 87851 0  8:32PM ttys000 0:00.77 -bash
501 8561  8560  0 12:36AM ttys001 0:00.04 -bash
A slide titled "PID" showing two columns: on the left "ps" labeled "Process Staus" and on the right "top" labeled "Table Of Processes", separated by a vertical divider.
Terminate processes using kill, which sends a signal to a PID. The default is SIGTERM (15) — a polite request to terminate. If the process won’t exit, SIGKILL (9) forces immediate termination.
SignalNumberMeaning
SIGTERM15Request graceful shutdown
SIGKILL9Force immediate termination
SIGHUP1Hangup — often sent when terminal closes
Examples:
# Send SIGTERM (default)
$ kill 99838

# Explicit forms
$ kill -15 99838
$ kill -TERM 99838

# Force kill with SIGKILL
$ kill -9 99838
$ kill -KILL 99838
For tracing system calls on Linux use strace. Useful flags:
  • -T : show time spent in each syscall
  • -f : follow child processes
  • -p <pid> : attach to an existing process
Example:
$ strace -T -f -p 99838
On macOS and other Unix-like systems, strace may not be available; alternatives include dtruss, truss, or ktrace (often requiring sudo). This attaches to PID 99838 and prints system call traces with timing while following child processes. Further reading and references: We’ll dive deeper into shell internals, job control, builtins vs external commands, and advanced techniques for managing long-running background work in later sections.

Watch Video