Friday, 13 March 2026

Understanding Foreground and Background Processes in Linux (fg, bg, Ctrl+C, Ctrl+Z)

 

Understanding Foreground and Background Processes in Linux (fg, bg, Ctrl+C, Ctrl+Z)

When working in the Linux terminal, it is important to understand how foreground processes, background processes, and job control work. Linux provides powerful keyboard signals and commands such as Ctrl+C, Ctrl+Z, bg, and fg to manage running programs.

In this article, we will explore these concepts using a simple Bash script and observe how Linux handles signals and process states.


Example Script

Below is a simple script that runs indefinitely and traps the SIGINT signal (Ctrl+C).

[root@oel01db Shell-Scripting]# cat o1-trap-with-sigint-with-no-exit.sh
#!/usr/bin/env bash

my-func() {
echo "hello world"
}

trap my-func SIGINT

while true; do
sleep 1
echo running
done
[root@oel01db Shell-Scripting]#

Running the Script

[root@oel01db Shell-Scripting]# bash o1-trap-with-sigint-with-no-exit.sh
running
running
running
running
^Chello world
running
running
^Chello world
running
running
^Z
[1]+ Stopped bash o1-trap-with-sigint-with-no-exit.sh
[root@oel01db Shell-Scripting]#

Understanding Ctrl+C and SIGINT

Normally, pressing Ctrl+C sends a signal called SIGINT (Signal Interrupt) to the running process.

The default behavior of SIGINT is to terminate the process immediately.

However, in our script we used:

trap my-func SIGINT

This means:

When SIGINT is received, do not terminate the program. Instead, run the function my-func.

So when Ctrl+C is pressed, the script prints:

hello world

and then continues running.

Because the function does not contain an exit command, the script keeps running indefinitely.

In other words, we have hijacked the default behavior of Ctrl+C.


Understanding Ctrl+Z and SIGTSTP

Unlike Ctrl+C, pressing Ctrl+Z sends a different signal called:

SIGTSTP (Terminal Stop)

This signal pauses the process instead of terminating it.

In our example:

^Z
[1]+ Stopped bash o1-trap-with-sigint-with-no-exit.sh

This means:

  • The process is not terminated

  • It is paused

  • It remains loaded in memory (RAM)

  • It consumes no CPU while stopped

The process is now waiting for instructions from the shell.


Viewing Jobs

Linux keeps track of suspended and background tasks as jobs.

You can list them using:

jobs

Each job is assigned a Job ID, displayed inside brackets like [1].


Moving a Stopped Job to the Background

If you type bg, the stopped job resumes execution but runs in the background.

[root@oel01db Shell-Scripting]# bg
[1]+ bash o1-trap-with-sigint-with-no-exit.sh &
[root@oel01db Shell-Scripting]# running
running
running
^C
[root@oel01db Shell-Scripting]# running
running
running

Important observation:

Even though the script runs in the background, its stdout is still connected to the terminal, so you continue to see the output.


Why Ctrl+C Does Not Work in the Background

When you pressed:

^C

nothing happened.

This is because keyboard signals like Ctrl+C are only sent to the foreground process group.

Since the script is running in the background, it does not receive the signal.


Bringing the Job Back to the Foreground

To interact with the job again, you must bring it to the foreground using the fg command.

[root@oel01db Shell-Scripting]# running
running
fg
bash o1-trap-with-sigint-with-no-exit.sh
running
running
^Z
[1]+ Stopped bash o1-trap-with-sigint-with-no-exit.sh
[root@oel01db Shell-Scripting]#

Step-by-step sequence

  1. Type fg and press Enter.

Note: You might have to type it while the word running is being printed repeatedly. Just type it and press Enter; Bash will still read it.

  1. The script returns to the foreground.

  2. The message appears again:

bash o1-trap-with-sigint-with-no-exit.sh
  1. The running messages continue.

  2. Now press Ctrl+Z again.

  3. The terminal immediately reports:

[1]+ Stopped

The script is now paused again.


Killing the Job

If you want to terminate the stopped job, first check the job list:

[root@oel01db Shell-Scripting]# jobs
[1]+ Stopped bash o1-trap-with-sigint-with-no-exit.sh
[root@oel01db Shell-Scripting]#

Then terminate it using the job ID:

[root@oel01db Shell-Scripting]# kill %1

[1]+ Stopped bash o1-trap-with-sigint-with-no-exit.sh
[root@oel01db Shell-Scripting]#
[1]+ Terminated bash o1-trap-with-sigint-with-no-exit.sh
[root@oel01db Shell-Scripting]#

The %1 refers to the job number [1].

We can also use kill %% to terminate the most recent job in the jobs list).


Important Job Control Commands

CommandPurpose
Ctrl+CSends SIGINT (terminate by default)
Ctrl+ZSends SIGTSTP (pause process)
jobsLists background and stopped jobs
bgResume a stopped job in background
fgBring a job to the foreground
kill %jobidTerminate a job

Useful Insight: Job IDs vs Process IDs

A job ID is managed by the shell.

Example:

[1]

But every job also has a real process ID (PID).

You can see it with:

ps

or

jobs -l

Example:

jobs -l
[1]+ 12345 Stopped bash o1-trap-with-sigint-with-no-exit.sh

Here:

  • 1 → Job ID

  • 12345 → Process ID


Real-World Importance

Understanding foreground and background processes is essential for:

  • running long scripts

  • managing database jobs

  • monitoring services

  • controlling log streams

  • writing robust shell scripts

  • handling signals safely

Linux job control allows you to pause, resume, move, and terminate processes without killing your terminal session, which is extremely powerful for system administrators and developers.

No comments:

Post a Comment

JFrog Artifactory - How to install

JFrog Artifactory OSS Installation Guide CentOS 9 + PostgreSQL 17 This guide provides a structured workflow to install JFrog Artifactory OSS...