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.