5月28日 02:12
How to perform error handling and debugging in Shell scripts? What are the common techniques?
Error handling and debugging techniques in Shell scripts are crucial for writing robust scripts.
Error Handling
Exit Status Codes
bash# Check command execution status command if [ $? -eq 0 ]; then echo "Command succeeded" else echo "Command failed with exit code $?" fi # Use && and || for conditional execution command1 && command2 # command2 executes only if command1 succeeds command1 || command2 # command2 executes only if command1 fails
set Command Options
bash# set -e: Exit immediately if any command fails set -e command1 command2 # Won't execute if command1 fails # set -u: Error when using undefined variables set -u echo $undefined_var # Error and exit # set -o pipefail: Return failure status if any command in pipe fails set -o pipefail command1 | command2 # Entire pipe fails if command1 fails # Combine options set -euo pipefail
Error Handling Functions
bash# Error handling function error_exit() { echo "Error: $1" >&2 exit 1 } # Check if file exists check_file() { if [ ! -f "$1" ]; then error_exit "File $1 not found" fi } # Use function check_file "config.txt"
trap Command
bash# Catch exit signals cleanup() { echo "Cleaning up..." rm -f /tmp/tempfile exit } # Catch EXIT signal trap cleanup EXIT # Catch INT signal (Ctrl+C) trap cleanup INT # Catch multiple signals trap cleanup EXIT INT TERM
Debugging Techniques
Debug Mode
bash# Enable debug mode set -x # Print each command set -v # Print input lines # Disable debug mode set +x set +v # Combine usage set -xv command1 command2 set +xv
Debug Output
bash# Use echo for debug output echo "Debug: variable = $variable" # Use printf for formatted output printf "Debug: %s = %s\n" "variable" "$variable" # Use >&2 to output to stderr echo "Debug info" >&2
Debug Functions
bash# Debug function debug() { if [ "$DEBUG" = "true" ]; then echo "[DEBUG] $*" >&2 fi } # Use debug function DEBUG=true debug "Processing file: $filename"
Variable Tracing
bash# Display variable values echo "var1 = $var1" echo "var2 = $var2" # Use declare to show variable information declare -p var1 declare -p var2 # Display all variables declare -p # Display all functions declare -f
Practical Application Examples
Robust Script Template
bash#!/bin/bash # Set error handling set -euo pipefail # Define error handling function error_exit() { echo "Error: $1" >&2 exit 1 } # Define cleanup function cleanup() { echo "Cleaning up..." [ -n "$tempfile" ] && rm -f "$tempfile" } # Set traps trap cleanup EXIT INT TERM # Define debug function debug() { if [ "${DEBUG:-false}" = "true" ]; then echo "[DEBUG] $*" >&2 fi } # Main function main() { debug "Starting script" # Check parameters if [ $# -lt 1 ]; then error_exit "Usage: $0 <filename>" fi local filename="$1" debug "Processing file: $filename" # Check file if [ ! -f "$filename" ]; then error_exit "File not found: $filename" fi # Create temp file tempfile=$(mktemp) || error_exit "Failed to create temp file" debug "Created temp file: $tempfile" # Process file cp "$filename" "$tempfile" # Processing logic... debug "Script completed successfully" } # Execute main function main "$@"
File Operations with Error Checking
bash#!/bin/bash # Safe file copy safe_copy() { local src="$1" local dst="$2" # Check source file if [ ! -f "$src" ]; then echo "Error: Source file not found: $src" >&2 return 1 fi # Check destination directory local dst_dir=$(dirname "$dst") if [ ! -d "$dst_dir" ]; then echo "Error: Destination directory not found: $dst_dir" >&2 return 1 fi # Check write permission if [ ! -w "$dst_dir" ]; then echo "Error: No write permission for: $dst_dir" >&2 return 1 fi # Execute copy if ! cp "$src" "$dst"; then echo "Error: Failed to copy $src to $dst" >&2 return 1 fi echo "Successfully copied $src to $dst" return 0 } # Use function safe_copy "source.txt" "destination.txt" || exit 1
Operations with Retry
bash#!/bin/bash # Function with retry retry_command() { local max_attempts="$1" shift local command=("$@") local attempt=1 while [ $attempt -le $max_attempts ]; do echo "Attempt $attempt of $max_attempts" if "${command[@]}"; then echo "Command succeeded" return 0 fi attempt=$((attempt + 1)) sleep 2 done echo "Command failed after $max_attempts attempts" >&2 return 1 } # Use function retry_command 3 curl -s http://example.com || exit 1
Logging
bash#!/bin/bash # Log function log() { local level="$1" shift local message="$*" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] [$level] $message" | tee -a script.log } log_info() { log "INFO" "$@" } log_error() { log "ERROR" "$@" } log_debug() { if [ "${DEBUG:-false}" = "true" ]; then log "DEBUG" "$@" fi } # Use log functions log_info "Script started" log_debug "Debug information" log_error "An error occurred"
Debugging Best Practices
- Use set -euo pipefail: Improve script robustness
- Use trap for cleanup: Ensure resources are properly released
- Use debug functions: Easy to control debug output
- Log events: Facilitate problem tracking and debugging
- Check command status: Use $? or if statements
- Use meaningful error messages: Help quickly locate problems
- Test edge cases: Ensure script works in various scenarios
- Use variable defaults:
${VAR:-default}prevents undefined variable errors