Bash: How to Exit a Script or Function Gracefully
Wed Aug 6th, 2025 — 13 days ago

Bash: How to Exit a Script or Function Gracefully

Problem

  • How do you exit or stop a running Bash script (or function) without closing your terminal session?
  • Sometimes you need to halt execution early due to errors, user requests, or special conditions, but you want to keep the shell open.

Solutions

In a Linux or macOS terminal:

  • Press CTRL+C to terminate (kill) a running script or command, and it will gracefully send a signal (SIGINT) to terminate the process.
  • Press CTRL+Z to pause/suspend the process (it keeps running, but is stopped and detached). You can later resume it with fg (foreground) or bg (background).

Note: Pressing CTRL+Z does not exit or stop the script for good—it only “pauses” it, leaving it suspended. To actually exit, use exit in your script, or terminate with CTRL+C. You can later resume that same process with the fg or bg commands.

What Are fg and bg Commands?

  • fg (foreground) resumes the most recently suspended job, running it in the foreground (terminal regains direct control).
  • bg (background) resumes the most recently suspended job, but lets it run in the background (you get your prompt back).

Examples of Suspending and Resuming a Bash Process

Let’s walk through a classic example:

# Example: Start a long-running script
$ bash myscript.sh

Suppose myscript.sh contains:

#!/bin/bash
echo "Start sleeping"
sleep 120
echo "Done"

Now, while it’s running (sleep 120), do:

  1. Suspend with CTRL+Z:
^Z
[1]+  Stopped                 bash myscript.sh

You get your shell prompt back. The script is “paused” (state: Stopped).

  1. Check jobs (optional):
$ jobs
[1]+  Stopped                 bash myscript.sh
  1. Resume in foreground:
$ fg
bash myscript.sh

Now it continues running in the foreground.

  1. Resume in background:
$ bg
[1]+ bash myscript.sh &

Script continues in the background; you get your shell prompt back immediately.

How to Stop Bash Programmatically

Here are a few ways you can stop a bash script, or bash process, programmatically:

  • Use exit to stop the script immediately:
#!/bin/bash
if [[ "$SOMETHING_WENT_WRONG" == "yes" ]]; then
  echo "Error: Something went wrong"
  exit 1  # Use a non-zero code for errors
fi
  • Exit with a custom status code (for error handling or automation):
exit 2  # Any non-zero value can indicate a specific failure
  • Use return to exit a sourced script or function programatically:
my_func() {
  echo "Exiting function early"
  return 1
}
my_func
echo "Script still running after function"
  • Trap signals for clean-up on exit:
trap 'echo "Cleaning up..."; exit 1' SIGINT
  • Graceful conditional exit anywhere in the script:
[[ -z "$REQUIRED_VAR" ]] && { echo "Missing var"; exit 1; }
  • Prompt user to exit interactively:
read -p "Continue? (y/n) " yn
[[ $yn != "y" ]] && exit 0
  • Kill script from another shell (advanced):
kill <pid_of_script>

Things to Consider

  • exit only closes the script, not your terminal or parent shell (unless the script was run with exec).
  • In functions or sourced scripts, use return to avoid killing the whole shell.
  • Use meaningful exit codes (convention: 0=success, 1-255=different errors).
  • Signal handling (using trap) can be useful for cleaning up temp files or resources.
  • Be aware of subshells: exit in a subshell affects only that subshell.

Gotchas

  • Repeatedly suspending scripts with CTRL+Z, instead of killing them with CTRL+C, leaves processes running in the background, eating up system resources and potentially causing port conflicts. Clean up suspended jobs with jobs and kill or bring them to the foreground with fg and terminate them properly.
  • Don’t use exit inside a function that’s sourced in your .bashrc—you might close your terminal!
  • exit in a sourced script exits the current shell, not just the script—prefer return.
  • Forgetting to check exit codes may result in silent failures.
  • kill-ing a script with kill -9 skips clean-up and traps, and often requires you to execute it with sudo privileges (which can be dangerous).

Sources


Further Investigation

  • Explore using trap for more robust error and signal handling.
  • Learn about bash set -e and its effect on script exit behavior.
  • Advanced Bash-Scripting Guide

Bash trap Command

trap is a Bash builtin that lets your script react, or do something, when it comes across signals or events. For example, you can run cleanup code (or any code) automatically before the script exits, or when it receives certain signals (like CTRL+C or script errors).

Here’s a practical example:

trap 'echo "Caught CTRL+C! Cleaning up..."; rm -f /tmp/myfile' SIGINT

Now, if you press CTRL+C while the script is running, it’ll print a message and remove the temp file (before exiting).


TL;DR

  • Press CTRL+C to terminate (kill) the running process.
  • Press CTRL+Z to pause/suspend a process, and use fg/bg to resume it.
  • Use exit to end a Bash script, or return in a function or sourced script.

Example:

exit 1  # exits script with error code 1

Note: Pressing CTRL+Z does not exit or stop the script for good—it only “pauses” it, leaving it suspended. To actually exit, use exit in your script, or terminate with CTRL+C. Pressing ^Z, when it’s a foreground process, truly “pauses” it wherever it is—mid-loop, mid-system call, or even in the middle of I/O.