Introduction

Hello! Today I’ll explain the set command.

The set command configures options that control shell behavior. Super useful when you want to debug scripts or change error handling behavior.

What is the set Command?

The set command is a Bash built-in for enabling/disabling shell options and setting positional parameters.

Use it when you want “scripts to stop on errors” or “errors on undefined variables”. Essential for writing serious scripts.

Basic Syntax

1
2
3
4
5
6
7
8
# Enable options
set -option

# Disable options
set +option

# Set positional parameters
set value1 value2 value3...

Main Options

Option Description
-e Exit script if command returns error
-u Error on undefined variables
-x Display commands before execution (debug)
-o pipefail Detect errors in pipelines
-n Check syntax only, don’t execute
-v Display commands before execution

Usage Examples

Example 1: Exit Immediately on Error (-e)

1
2
3
4
5
6
#!/bin/bash
set -e

echo "Process 1"
false  # Error command
echo "Process 2"  # Not executed

Output:

1
Process 1

The false command errors out and stops the script. Without set -e, it would ignore the error and continue.

Example 2: Error on Undefined Variables (-u)

1
2
3
4
5
6
#!/bin/bash
set -u

NAME="John"
echo $NAME
echo $AGE  # Error on undefined variable

Output:

1
2
John
bash: AGE: unbound variable

Prevents bugs from typos.

Example 3: Debug Mode (-x)

1
2
3
4
5
6
#!/bin/bash
set -x

name="John"
age=30
echo "Name: $name, Age: $age"

Output:

1
2
3
4
+ name=John
+ age=30
+ echo 'Name: John, Age: 30'
Name: John, Age: 30

Executed commands are shown with +. Super handy.

Example 4: Detect Pipeline Errors

1
2
3
4
5
6
#!/bin/bash
set -o pipefail

# Error in middle of pipeline
cat nonexistent.txt | grep "test" | wc -l
echo "Exit code: $?"

Output:

1
2
cat: nonexistent.txt: No such file or directory
Exit code: 1

Without set -o pipefail, the exit code would be 0 since wc -l succeeds.

Example 5: Combining Multiple Options

1
2
3
4
5
#!/bin/bash
# Common combination
set -euo pipefail

echo "Safe script execution"

or

1
2
3
4
5
#!/bin/bash
set -eux
set -o pipefail

echo "Strict mode + debug"

Example 6: Setting Positional Parameters

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Display current positional parameters
echo "$@"

# Set new values
set apple banana orange

echo "Arg 1: $1"
echo "Arg 2: $2"
echo "Arg 3: $3"
echo "All args: $@"

Output:

1
2
3
4
Arg 1: apple
Arg 2: banana
Arg 3: orange
All args: apple banana orange

Example 7: Disabling Options

1
2
3
4
5
6
7
8
#!/bin/bash
set -x  # Enable debug

echo "Debugging"

set +x  # Disable debug

echo "Normal execution"

Output:

1
2
3
+ echo Debugging
Debugging
Normal execution

Use + to disable.

Tips & Notes

set -e Gotchas

set -e is useful but gets disabled inside conditionals.

1
2
3
4
5
6
7
8
#!/bin/bash
set -e

if false; then
    echo "Not executed"
fi

echo "This executes"  # Doesn't stop on error!

If you don’t want this behavior, check explicitly.

1
2
3
4
5
6
7
#!/bin/bash
set -e

if ! some_command; then
    echo "Command failed" >&2
    exit 1
fi

Check Current Options

1
2
# Display enabled options
set -o

or

1
echo $-

Write at Script Top

Recommended to write set options at script top.

1
2
3
4
5
6
#!/bin/bash
# Recommended script header
set -euo pipefail
IFS=$'\n\t'

# Main processing starts here

Temporarily Change Options

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
set -e

# Temporarily disable -e
set +e
might_fail_command
result=$?
set -e

if [ $result -ne 0 ]; then
    echo "Command failed"
fi

Practical Usage

Production Scripts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash
# Exit immediately on error
set -euo pipefail

# Log file
LOG_FILE="/var/log/myapp.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

log "Backup started"
tar -czf backup.tar.gz /data
log "Backup completed"

Debug Scripts

1
2
3
4
5
6
7
8
9
#!/bin/bash
# Debug mode detection
if [ "${DEBUG:-}" = "1" ]; then
    set -x
fi

set -euo pipefail

# Processing...

Run with:

1
2
3
4
5
# Normal
./script.sh

# Debug
DEBUG=1 ./script.sh

Error Handling

1
2
3
4
5
6
7
8
9
#!/bin/bash
set -euo pipefail

# Error handler
trap 'echo "Error occurred: line $LINENO" >&2' ERR

echo "Process 1"
false  # Error
echo "Process 2"

Output:

1
2
Process 1
Error occurred: line 7

File Processing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash
set -euo pipefail

# Read from file and set positional parameters
set -- $(cat files.txt)

for file in "$@"; do
    echo "Processing: $file"
    process_file "$file"
done

Environment Variable Defaults

1
2
3
4
5
6
7
8
#!/bin/bash
set -euo pipefail

# Error on undefined but allow defaults
DATABASE_HOST="${DATABASE_HOST:-localhost}"
DATABASE_PORT="${DATABASE_PORT:-5432}"

echo "Connecting to: $DATABASE_HOST:$DATABASE_PORT"

Common set Option Combinations

Strict Mode

1
2
3
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

This is Bash script best practice.

  • -e: Exit on error
  • -u: Error on undefined variables
  • -o pipefail: Detect pipeline errors
  • IFS=$'\n\t': Safe delimiter settings

Debug Mode

1
2
#!/bin/bash
set -xeuo pipefail

or conditional:

1
2
3
#!/bin/bash
[ "${DEBUG:-0}" = "1" ] && set -x
set -euo pipefail

Summary

Key points about the set command:

  • -e: Exit immediately on error (recommended)
  • -u: Error on undefined variables (recommended)
  • -x: Display commands for debugging
  • -o pipefail: Detect pipeline errors (recommended)
  • - to enable, + to disable
  • Best practice: set -euo pipefail at script top

For serious scripts, you should at least include set -e!