Skip to main content
In Bash and other POSIX-compatible shells, special variables like $$ and $! help you manage process IDs (PIDs) for debugging, automation, and scripting tasks. While they might not pop up every day, knowing how to use them can streamline background jobs, service management, and process monitoring. Before diving into these variables, let’s clarify how TTYs, shells, and PIDs relate:
  1. When you open a terminal, it’s assigned a TTY (teletype) name.
  2. A shell (e.g., Bash) runs on that TTY and acts as the parent process.
  3. Any command or script executed in that shell becomes a child process.
  4. Every process—from parent shells to background jobs—has a PID and a lifecycle (start → run → exit).

Table of Special PID Variables


Using $! to Capture Background Job PIDs

The $! variable returns the PID of the last job you sent to the background.
Even if you run foreground commands afterward, $! holds the PID until you start another background job:

Storing $! in a Bash Script

A common pattern is launching a service in the background, capturing its PID, and later terminating it. For example, starting an Apache JMeter server:

Using $$ to Identify Your Shell or Script

The $$ variable prints the PID of the current shell or script process:
Opening a new terminal tab or window yields a different $$ value:

Inspecting $$ Inside a Script

Create print_pid.sh:
Run it in the background:
  • PID 94479 corresponds to the script itself ($$).
  • PID 94481 is the child sleep process.

$$ and Subshell Behavior

Subshells inherit the parent shell’s PID, so $$ stays constant:
Output:
All references to $$ show the same PID because subshells share the parent’s process ID.

Key Takeaways

  • $! returns the PID of the last command run in the background.
  • $$ returns the PID of your current shell or the running script.
Understanding these variables will help you write more robust scripts, automate process control, and debug complex workflows with confidence.

Watch Video