shell-error-handling
$
npx mdskill add TheBushidoCollective/han/shell-error-handlingImplement robust shell scripting by managing exit codes, traps, and cleanup routines.
- Ensures scripts reliably clean up resources and handle unexpected failures gracefully.
- Leverages core shell utilities like Bash, Read, Write, and Write for execution.
- Guides the agent to correctly structure error checks and resource management blocks.
- Provides executable code snippets demonstrating best practices for shell scripting.
SKILL.md
.github/skills/shell-error-handlingView on GitHub ↗
---
name: shell-error-handling
user-invocable: false
description: Use when implementing error handling, cleanup routines, or debugging in shell scripts. Covers traps, exit codes, and robust error patterns.
allowed-tools:
- Read
- Write
- Edit
- Bash
- Grep
- Glob
---
# Shell Error Handling
Patterns for robust error handling, cleanup, and debugging in shell scripts.
## Exit Codes
### Standard Exit Codes
| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | General error |
| 2 | Misuse of shell command |
| 126 | Command not executable |
| 127 | Command not found |
| 128+N | Fatal signal N |
| 130 | Ctrl+C (SIGINT) |
### Checking Exit Status
```bash
# Check last command's exit status
if ! command; then
echo "Command failed with status $?" >&2
exit 1
fi
# Alternative pattern
command || {
echo "Command failed" >&2
exit 1
}
# Capture exit status
command
status=$?
if (( status != 0 )); then
echo "Failed with status $status" >&2
fi
```
## Trap for Cleanup
### Basic Cleanup Pattern
```bash
#!/usr/bin/env bash
set -euo pipefail
cleanup() {
local exit_code=$?
# Remove temporary files
rm -f "$TEMP_FILE" 2>/dev/null || true
exit "$exit_code"
}
trap cleanup EXIT
TEMP_FILE=$(mktemp)
# Script continues...
# cleanup runs automatically on exit
```
### Handling Multiple Signals
```bash
#!/usr/bin/env bash
set -euo pipefail
cleanup() {
echo "Cleaning up..." >&2
rm -rf "$WORK_DIR" 2>/dev/null || true
}
handle_interrupt() {
echo "Interrupted by user" >&2
cleanup
exit 130
}
trap cleanup EXIT
trap handle_interrupt INT TERM
WORK_DIR=$(mktemp -d)
```
### Trap Best Practices
```bash
# Preserve original exit code in cleanup
cleanup() {
local exit_code=$?
# Cleanup operations here
rm -f "$temp_file" 2>/dev/null || true
# Restore exit code
exit "$exit_code"
}
# Use || true for optional cleanup
trap 'rm -f "$temp_file" 2>/dev/null || true' EXIT
```
## Error Reporting
### Standard Error Output
```bash
# Always write errors to stderr
echo "Error: Something went wrong" >&2
# Error function
error() {
echo "Error: $*" >&2
}
# Die function - error and exit
die() {
echo "Fatal: $*" >&2
exit 1
}
# Usage
[[ -f "$config" ]] || die "Config file not found: $config"
```
### Verbose Logging
```bash
#!/usr/bin/env bash
set -euo pipefail
VERBOSE="${VERBOSE:-false}"
log() {
if [[ "$VERBOSE" == "true" ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
fi
}
error() {
echo "[ERROR] $*" >&2
}
log "Starting script"
log "Processing file: $file"
```
## Defensive Programming
### Check Prerequisites
```bash
# Check required commands exist
require_command() {
command -v "$1" >/dev/null 2>&1 || {
echo "Error: Required command '$1' not found" >&2
exit 1
}
}
require_command jq
require_command curl
require_command shellcheck
```
### Validate Input
```bash
# Validate arguments
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <source> <destination>" >&2
exit 1
fi
source_file="$1"
dest_dir="$2"
# Validate file exists
[[ -f "$source_file" ]] || {
echo "Error: Source file not found: $source_file" >&2
exit 1
}
# Validate directory
[[ -d "$dest_dir" ]] || {
echo "Error: Destination directory not found: $dest_dir" >&2
exit 1
}
```
### Safe Temporary Files
```bash
# Create secure temp file
TEMP_FILE=$(mktemp) || {
echo "Error: Failed to create temp file" >&2
exit 1
}
# Create secure temp directory
TEMP_DIR=$(mktemp -d) || {
echo "Error: Failed to create temp directory" >&2
exit 1
}
# Always clean up
trap 'rm -rf "$TEMP_FILE" "$TEMP_DIR" 2>/dev/null || true' EXIT
```
## Debugging
### Debug Mode
```bash
#!/usr/bin/env bash
# Enable debug mode via environment variable
if [[ "${DEBUG:-}" == "1" ]]; then
set -x
fi
set -euo pipefail
# Or toggle with a flag
while getopts "d" opt; do
case $opt in
d) set -x ;;
*) echo "Usage: $0 [-d]" >&2; exit 1 ;;
esac
done
```
### Trace Execution
```bash
# Enable tracing for specific section
set -x
problematic_code
set +x
# Trace with custom PS4
export PS4='+ ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -x
```
## Error Recovery Patterns
### Retry Pattern
```bash
retry() {
local max_attempts="${1:-3}"
local delay="${2:-1}"
shift 2
local cmd=("$@")
local attempt=1
while (( attempt <= max_attempts )); do
if "${cmd[@]}"; then
return 0
fi
echo "Attempt $attempt failed, retrying in ${delay}s..." >&2
sleep "$delay"
(( attempt++ ))
done
echo "All $max_attempts attempts failed" >&2
return 1
}
# Usage
retry 3 5 curl -f "http://example.com/api"
```
### Fallback Pattern
```bash
# Try primary, fall back to secondary
get_config() {
if [[ -f "$HOME/.config/myapp/config" ]]; then
cat "$HOME/.config/myapp/config"
elif [[ -f "/etc/myapp/config" ]]; then
cat "/etc/myapp/config"
else
echo "Error: No config file found" >&2
return 1
fi
}
```
More from TheBushidoCollective/han
- absinthe-resolversUse when implementing GraphQL resolvers with Absinthe. Covers resolver patterns, dataloader integration, batching, and error handling.
- absinthe-schemaUse when designing GraphQL schemas with Absinthe. Covers type definitions, interfaces, unions, enums, and schema organization patterns.
- absinthe-subscriptionsUse when implementing real-time GraphQL subscriptions with Absinthe. Covers Phoenix channels, PubSub, and subscription patterns.
- act-docker-setupUse when configuring Docker environments for act, selecting runner images, managing container resources, or troubleshooting Docker-related issues with local GitHub Actions testing.
- act-local-testingUse when testing GitHub Actions workflows locally with act. Covers act CLI usage, Docker configuration, debugging workflows, and troubleshooting common issues when running workflows on your local machine.
- act-workflow-syntaxUse when creating or modifying GitHub Actions workflow files. Provides guidance on workflow syntax, triggers, jobs, steps, and expressions for creating valid GitHub Actions workflows that can be tested locally with act.
- ameba-configurationUse when configuring Ameba rules and settings for Crystal projects including .ameba.yml setup, rule management, severity levels, and code quality enforcement.
- ameba-custom-rulesUse when creating custom Ameba rules for Crystal code analysis including rule development, AST traversal, issue reporting, and rule testing.
- ameba-integrationUse when integrating Ameba into development workflows including CI/CD pipelines, pre-commit hooks, GitHub Actions, and automated code review processes.
- analyze-performanceAnalyze performance metrics and identify slow transactions in Sentry