Understanding ‘set -e’ in Shell Scripting: Benefits, Risks, and Practical Examples


2 views

The set -e command is a fundamental shell option that causes a script to exit immediately if any command returns a non-zero exit status (indicating failure). This behavior is particularly useful for:

#!/bin/bash
set -e
rm critical_file.tmp
echo "This line won't execute if rm fails"

System administrators frequently employ set -e in scenarios where:

  • Configuration management scripts
  • Deployment automation
  • Critical system maintenance tasks

Example of safe usage pattern:

#!/bin/bash
set -e
backup_dir="/var/backups"
mkdir -p "$backup_dir"
tar -czf "$backup_dir/app_$(date +%F).tar.gz" /opt/app

While powerful, set -e becomes dangerous when:

#!/bin/bash
set -e
grep "error" logfile || true  # Without '|| true', script would exit
status_code=$(curl -s -o /dev/null -w "%{http_code}" example.com)

The second line demonstrates a common pitfall - command substitutions don't trigger set -e, potentially hiding failures.

Consider this database backup script that went wrong:

#!/bin/bash
set -e
pg_dump -U user db > backup.sql
aws s3 cp backup.sql s3://bucket/  # If this fails, the script exits
rm backup.sql  # File gets deleted even if upload failed

To mitigate risks while maintaining failure sensitivity:

#!/bin/bash
set -euo pipefail  # Combines with other safety options
trap 'echo "Error at line $LINENO"; exit 1' ERR

temp_file=$(mktemp)
cleanup() { rm -f "$temp_file"; }
trap cleanup EXIT

# Main script logic here

For complex error handling needs:

#!/bin/bash
error_handler() {
    echo "Error occurred in $1" >&2
    exit 1
}

command1 || error_handler "command1"
command2 || error_handler "command2"

Certain scenarios warrant disabling this behavior:

#!/bin/bash
# Section where failures are expected
set +e
count=$(grep -c "pattern" file)
set -e

if (( count > 0 )); then
    handle_matches
fi

The set -e command is a shell option that causes a script to exit immediately if any command returns a non-zero exit status (indicating failure). This behavior is often referred to as "errexit" or "exit on error."

#!/bin/bash
set -e
nonexistent_command  # This will cause the script to exit
echo "This line won't be executed"

Many programmers use set -e to make their scripts more robust by:

  • Preventing silent failures
  • Ensuring early termination when something goes wrong
  • Making error handling more predictable

Despite its usefulness, set -e has several surprising behaviors that can make scripts behave unexpectedly:

#!/bin/bash
set -e
false | true  # The pipe succeeds despite 'false' failing
echo "This line executes because the pipeline succeeds"

Other problematic cases include:

  • Commands in conditionals (if, while, until)
  • Functions that check return codes
  • Commands in command substitution $(...)

Consider this common pattern that fails with set -e:

#!/bin/bash
set -e
if ! grep "pattern" file.txt; then
    echo "Pattern not found"  # This might never execute
fi

Instead of relying solely on set -e, consider:

#!/bin/bash
set -eo pipefail  # More strict version
# Or explicit error checking:
command || { echo "Error occurred"; exit 1; }

set -e can be useful in:

  • Simple, linear scripts
  • Cases where any failure should abort the entire operation
  • Combination with trap for cleanup
#!/bin/bash
set -e
trap 'cleanup_function' EXIT
# Rest of script...