How to Force Successful Exit Status in Bash Regardless of Command Failure (for sh -e Scripts)


2 views

When using sh -e or set -e in bash scripts, any command returning non-zero exit status will cause immediate script termination. However, sometimes we need to intentionally ignore failures of specific commands while maintaining strict error checking for the rest of the script.

1. The OR Operator Approach

Appending || true forces a successful exit status:

#!/bin/bash
set -e

# This will not stop the script even if command fails
problematic_command || true

echo "Script continues after potential failure"

2. The If Statement Pattern

More verbose but allows handling different outcomes:

#!/bin/bash
set -e

if ! problematic_command; then
    echo "Command failed, but we're continuing anyway" >&2
fi

critical_command_that_must_succeed

3. Temporary Error Checking Disable

For complex command groups:

#!/bin/bash
set -e

set +e
problematic_command_1
problematic_command_2
set -e

echo "Resumed strict error checking"

CI/CD Pipelines: You might want to run non-critical tests without failing the entire pipeline:

run_unit_tests || true
run_integration_tests  # This one must succeed

Cleanup Operations: Where failure of cleanup shouldn't prevent main logic:

temp_cleanup() {
    rm -rf /tmp/mytemp* || true
}

For complex scenarios, consider trap-based solutions:

#!/bin/bash
set -e

handle_error() {
    echo "Error occurred but continuing" >&2
    return 0
}

trap handle_error ERR
problematic_command
trap - ERR  # Reset the trap

Remember that while suppressing errors can be useful, it should be done judiciously to avoid masking genuine problems in your scripts.


When working with sh -ex or bash -e, the shell immediately exits when any command returns a non-zero exit status. This strict error handling is generally useful, but there are cases where we want to continue execution even if specific commands fail.

The simplest way to force a successful exit status is using the OR operator (||):

your_command || true

This works because:

  • If your_command succeeds (returns 0), the OR condition short-circuits
  • If your_command fails, true executes and returns 0

For more complex scenarios, consider these methods:

1. Explicit Exit Status Override

your_command || exit_code=$?
echo "Command completed with $exit_code, but continuing anyway"

2. Temporary Error Handling Disable

set +e
your_command
set -e

3. Using Subshells for Isolation

(your_command) || true

Here's how this technique helps in practical scenarios:

Example 1: Optional Dependency Check

# Check for optional tool without failing the script
which optional_tool || true

Example 2: Non-Critical Cleanup

# Attempt cleanup, but proceed even if it fails
rm -rf /tmp/tempfiles* || true

Example 3: Conditional Step in CI Pipeline

# Try to deploy to staging, continue if it fails
./deploy_to_staging.sh || echo "Staging deploy failed, continuing with production"

While these techniques are useful, be aware that:

  • Overusing this pattern can mask important failures
  • In production scripts, consider logging the actual exit status
  • For critical commands, proper error handling is still recommended

The choice between these methods depends on your specific requirements for error visibility versus script continuation.