DEV Community

Cover image for set -euo pipefail — the Line That Would Have Saved Me from Deleting the Wrong Directory
Anguishe
Anguishe

Posted on • Originally published at bashsnippets.xyz

set -euo pipefail — the Line That Would Have Saved Me from Deleting the Wrong Directory

Here's a script that will ruin your day:

#!/bin/bash
cd /nonexistent/folder
rm -rf *
echo "Done"
Enter fullscreen mode Exit fullscreen mode

The cd fails because the folder doesn't exist. Bash ignores the failure. rm -rf * runs in whatever directory you were already in. The script prints "Done." You have no idea anything went wrong until you notice your files are gone.

This isn't a contrived example. This is the actual failure mode of every bash script that doesn't have error handling. Bash's default behavior is to keep running after errors. Every command after a failure executes as if everything is fine. It's the most dangerous default in the entire language.

Two lines fix it.


The Template

#!/bin/bash
set -euo pipefail

trap 'echo "Error on line $LINENO — script stopped." >&2' ERR

# Your script starts here
Enter fullscreen mode Exit fullscreen mode

Add this to the top of every script you write. Every single one. No exceptions.


What Each Flag Does

-e (errexit) — Stop the script immediately if any command exits with a non-zero status. This is the one that prevents the cd + rm disaster above. If cd fails, the script stops right there. rm never runs.

-u (nounset) — Treat any undefined variable as an error. Without this, $UNDEFINED_VAR silently becomes an empty string. Imagine this:

BACKUP_DIR=""  # Oops, forgot to set this
rm -rf "$BACKUP_DIR"/*
Enter fullscreen mode Exit fullscreen mode

That expands to rm -rf /*. That's your entire filesystem. With -u, bash catches the empty variable and stops before the rm ever runs.

-o pipefail — Make a pipeline fail if ANY command in it fails, not just the last one. Without this:

cat nonexistent-file.txt | grep "pattern" | wc -l
Enter fullscreen mode Exit fullscreen mode

cat fails, but grep gets empty input, and wc -l counts zero lines and exits successfully. The pipeline reports success even though the first command failed. With pipefail, the pipeline's exit status is the failure from cat, so -e catches it.


The trap Line

trap 'echo "Error on line $LINENO — script stopped." >&2' ERR
Enter fullscreen mode Exit fullscreen mode

This tells bash: "When an error happens, before you exit, run this command." It prints which line number failed and writes to stderr (>&2). Without this, the script just stops silently and you have to guess which line caused it.

In a 200-line script, "it failed somewhere" is useless. "Error on line 47" is actionable.


The Real-World Difference

Without error handling:

#!/bin/bash
cd /tmp/build
make
make install
echo "Build complete"
Enter fullscreen mode Exit fullscreen mode

If cd fails (the directory doesn't exist), make runs in the wrong directory. If make fails (compilation error), make install installs whatever was there from last time. The script prints "Build complete" regardless.

With error handling:

#!/bin/bash
set -euo pipefail
trap 'echo "Error on line $LINENO" >&2' ERR

cd /tmp/build
make
make install
echo "Build complete"
Enter fullscreen mode Exit fullscreen mode

If cd fails, the script stops and prints "Error on line 5." If make fails, same thing. echo "Build complete" only runs if every single command before it succeeded.


The One Gotcha

set -e changes how you write conditional logic. This fails:

set -e
grep "pattern" file.txt  # exits 1 if pattern not found
echo "This never runs"
Enter fullscreen mode Exit fullscreen mode

grep returns exit code 1 when it finds no matches. With -e, that's treated as an error and the script stops. But you didn't want it to stop — you just wanted to check if the pattern exists.

The fix is to use it in a conditional:

set -e
if grep -q "pattern" file.txt; then
  echo "Found it"
else
  echo "Not found"
fi
Enter fullscreen mode Exit fullscreen mode

When a command is part of an if condition, -e doesn't trigger on its exit code. This is the standard pattern.

Or suppress the exit code explicitly:

grep "pattern" file.txt || true
Enter fullscreen mode Exit fullscreen mode

The || true means "if grep fails, run true instead" — and true always succeeds, so -e doesn't trigger.


Where to Go from Here

Every script on BashSnippets.xyz uses set -euo pipefail and the CHECK="✓" / CROSS="✗" pattern. If you want a head start, the Bash Boilerplate Generator builds a complete script template with error handling, logging, and cleanup traps already configured. Pick your options, copy the output, and start writing from a safe foundation.


Full breakdown with more examples, the trap pattern, and common pitfalls:

bashsnippets.xyz/snippets/bash-error-handling.html

If you only take one thing from this: add set -euo pipefail to the top of every script. It takes 3 seconds and prevents the kind of failures that take hours to recover from.

Top comments (0)