Operations 12 min read

How to Make Bash Scripts Self‑Terminate Cleanly with Traps and Kill

This article explains why background loops in Bash scripts survive script termination, shows how they become orphaned under init/systemd, and provides robust techniques—including kill, killall, pkill, and trap handlers—to ensure all child processes are terminated when the script exits.

Linux Cloud Computing Practice
Linux Cloud Computing Practice
Linux Cloud Computing Practice
How to Make Bash Scripts Self‑Terminate Cleanly with Traps and Kill

1. Script Self‑Termination

When a Bash script launches background tasks (for example sleep 50 &) and then reaches the end of its flow, those background processes are re‑parented to init / systemd and continue running after the script exits.

# cat test1.sh
#!/bin/bash
echo $BASHPID
sleep 50 &

After the script finishes, the sleep process’s parent PID becomes 1. Killing the script’s main PID does not stop the background sleep because a second shell process created for the while loop remains.

# cat test1.sh (with kill)
#!/bin/bash
echo $BASHPID
while true; do
    sleep 50
    echo 1
done &
kill $!

If the background loop is placed inside while, for or until, simply killing $BASHPID is insufficient; an additional shell process that provides the loop’s execution environment stays alive and its children are inherited by init.

To analyze the situation, a second script test2.sh can be created:

#!/bin/bash
echo $BASHPID
while true; do
    sleep 50
    echo 1
done &
sleep 60

Running pstree -p | grep test2.sh reveals two test2.sh processes: one is the script itself, the other is a subshell that hosts the background while. When the main script is killed, the subshell is re‑parented to init and continues looping.

One simple way to achieve “script suicide” is to kill all processes that share the script’s name before the script exits:

# cat test1.sh (basic killall)
#!/bin/bash
echo $BASHPID
while true; do
    sleep 50
    echo 1
done &
killall `basename $0`

However, this approach fails when the script is invoked as bash test1.sh because the process name becomes bash. A more robust solution uses pkill -f together with the background job’s PID ( $!).

# cat test1.sh (robust version)
#!/bin/bash
trap "pkill -f $(basename $0)" SIGINT

echo $BASHPID
while true; do
    sleep 50
    echo 1
done &
pid=$!
kill $pid
pkill -f $(basename $0)

A fully generic version places all cleanup commands in a trap that handles SIGINT, SIGTERM, EXIT and ERR:

#!/bin/bash
trap "pkill -f $(basename $0); exit 1" SIGINT SIGTERM EXIT ERR
while true; do
    sleep 1
    echo \"hello world!\"
done &
# other foreground work …
sleep 60

Another concise method uses the special PID 0 with kill. Sending a signal to PID 0 delivers it to every process in the current process group, effectively terminating the script and all its children:

#!/bin/bash
trap "echo 'signal_handled:'; kill 0" SIGINT SIGTERM
while true; do
    sleep 5
    echo \"hello world! hello world!\"
done &
sleep 60

2. Special Nature of Bash Built‑ins

Built‑in commands such as while, for, until, if and case rely on a Bash process to provide an execution environment. When they are run in the background, Bash spawns a new subshell (a new Bash process) to host them.

If the background command is started from an interactive shell, the parent is a newly created Bash process.

If it is started from a script, the script’s own Bash process acts as the parent.

When the parent Bash process is killed, the subshell (and any processes it created) become children of init / systemd. Non‑built‑in commands do not have this dependency and can be terminated directly.

Examples such as if true; then sleep 10; fi & or while true; do sleep 2; done & demonstrate that a new Bash process appears (visible with pstree) before the actual background command runs.

Understanding this behavior is essential for reliable script cleanup, especially when scripts contain long‑running background loops that must be stopped when the script receives Ctrl+C or other termination signals.

For further reading, see the original article at https://www.cnblogs.com/f-ck-need-u/p/8661501.html (copyright belongs to the original author).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Bashtrapscript self‑termination
Linux Cloud Computing Practice
Written by

Linux Cloud Computing Practice

Welcome to Linux Cloud Computing Practice. We offer high-quality articles on Linux, cloud computing, DevOps, networking and related topics. Dive in and start your Linux cloud computing journey!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.