Command documentation sourced from the linux-command project This comprehensive command reference is part of the linux-command documentation project.
set - Shell Options and Positional Parameters
The set command is a built-in shell command that displays or sets shell attributes and positional parameters. It is one of the most fundamental and powerful tools for shell scripting and interactive shell usage. The set command controls shell behavior through various options, manages environment variables, handles debugging, and provides access to shell positional parameters. It works with Bourne-like shells including bash, sh, ksh, and zsh, though specific options may vary between shell implementations.
Basic Syntax
set [-abefhkmnptuvxBCHP] [-o option-name] [argument ...]
set [+abefhkmnptuvxBCHP] [+o option-name] [argument ...]
set -- [argument ...]
set -o
set +o
Common Shell Options
Option Categories
Debugging and Error Handling
-e/-o errexit- Exit immediately if a command exits with a non-zero status-u/-o nounset- Treat unset variables as an error when substituting-o pipefail- The return value of a pipeline is the status of the last command to exit with a non-zero status-x/-o xtrace- Print commands and their arguments as they are executed-v/-o verbose- Print shell input lines as they are read
Job Control
-m/-o monitor- Enable job control (default for interactive shells)-b/-o notify- Report the status of terminated background jobs immediately
File Expansion and Globbing
-f/-o noglob- Disable pathname expansion-C/-o noclobber- Prevent output redirection from overwriting existing files
History and Interactive Features
-H/-o histexpand- Enable!style history substitution (default for interactive shells)-o history- Enable command history
Other Important Options
-a/-o allexport- Automatically export variables to child processes-n/-o noexec- Read commands but do not execute them (syntax check)-h/-o hashall- Remember command locations as they're looked up-k/-o keyword- All arguments in the form of assignment statements are placed in the environment-p/-o privileged- When set, the shell does not read profile files-t/-o onecmd- Exit after reading and executing one command-B/-o braceexpand- Enable brace expansion (default)-P/-o physical- Do not follow symbolic links when changing directories
Usage Examples
Basic Shell Option Management
Viewing Current Options
# Show all current shell options
set -o
# Show all current shell options in a compact format
set +o
# Show only enabled options
echo $-
# Display shell configuration
set
Setting and Unsetting Options
# Enable exit on error
set -e
set -o errexit
# Disable exit on error
set +e
set +o errexit
# Treat unset variables as errors
set -u
set -o nounset
# Enable debugging mode
set -x
set -o xtrace
# Enable verbose mode
set -v
set -o verbose
# Enable pipe failure checking
set -o pipefail
# Disable filename expansion
set -f
set -o noglob
Multiple Options at Once
# Enable multiple options
set -euxo pipefail
# Equivalent to: set -e -u -x -o pipefail
# Disable multiple options
set +fxv
# Equivalent to: set +f +x +v
# Common debugging combination
set -xv # Enable both trace and verbose
Positional Parameters Management
Setting Positional Parameters
# Set positional parameters directly
set -- arg1 arg2 arg3
# Set with shell expansion
set -- *.txt
# Set from command output
set -- $(find . -name "*.log")
# Clear all positional parameters
set --
Working with Positional Parameters
# Set sample parameters
set -- apple banana cherry date
# Access individual parameters
echo "$1" # apple
echo "$2" # banana
echo "$3" # cherry
echo "$4" # date
# Access all parameters
echo "$@" # apple banana cherry date (separate arguments)
echo "$*" # apple banana cherry date (single string)
# Count parameters
echo "$#" # 4
# Shift parameters
shift # Remove first parameter
echo "$1" # banana (now first)
echo "$2" # cherry
Advanced Parameter Manipulation
# Set parameters from array
array=(one two three four)
set -- "${array[@]}"
# Set parameters with whitespace handling
set -- "first item" "second item" "third item"
# Process command line arguments
set -- "$@"
while [ $# -gt 0 ]; do
case "$1" in
-h|--help) echo "Help requested"; shift ;;
-v|--verbose) VERBOSE=1; shift ;;
*) echo "Unknown option: $1"; shift ;;
esac
done
Script Debugging and Error Handling
Error Handling Scripts
#!/bin/bash
# Strict error handling
set -euo pipefail
# This script will exit on any error
echo "Starting script..."
# This will cause exit if file doesn't exist
cat nonexistent_file.txt
# This will cause exit if variable is unset
echo "$UNSET_VARIABLE"
echo "This line will not be reached"
Debugging Scripts
#!/bin/bash
# Enable debugging
set -x
# Debug function calls
my_function() {
echo "Inside function with args: $@"
}
# Debug variable assignments
DEBUG_MODE=1
CONFIG_FILE="/etc/myapp.conf"
# Debug command execution
if [[ -f "$CONFIG_FILE" ]]; then
echo "Config file exists"
fi
# Debug loops
for i in {1..5}; do
echo "Iteration $i"
done
# Disable debugging
set +x
Development and Testing Mode
#!/bin/bash
# Development mode - syntax checking only
set -n
# This will be checked for syntax but not executed
echo "This won't run"
for file in *.txt; do
echo "Processing $file"
done
# After syntax check, run for real
set +n
echo "Now executing..."
File and Directory Operations
Safe File Operations
# Prevent accidental overwrites
set -C
# This will fail if file exists
echo "content" > existing_file.txt
# This will succeed (append)
echo "more content" >> existing_file.txt
# Temporarily allow overwrites
set +C
echo "overwrite" > existing_file.txt
Directory Navigation
# Use physical path resolution
set -P
cd /var/../etc # Goes to /etc directly, not through symlinks
# Use logical path resolution (default)
set +P
cd /var/../etc # May follow symbolic links
Environment and Variable Management
Auto-export Variables
# Enable automatic export
set -a
# Variables will be automatically exported
CONFIG_DIR="/etc/myapp"
LOG_LEVEL="debug"
MAX_CONNECTIONS=100
# Run command with exported variables
./myapp
# Disable auto-export
set +a
Variable Safety
# Treat unset variables as errors
set -u
# This will fail
echo "$UNSET_VAR"
# Provide default values to avoid errors
echo "${VAR:-default_value}"
# Check if variable is set
if [[ -v VAR ]]; then
echo "VAR is set: $VAR"
else
echo "VAR is not set"
fi
Pipeline Error Handling
Pipeline Failure Detection
# Enable pipefail option
set -o pipefail
# Pipeline will fail if any command fails
cat config.txt | grep -i "error" | sort
# The exit status will be non-zero if any command fails
if ! cat config.txt | grep -i "error" | sort > output.txt; then
echo "Pipeline failed"
fi
# Handle pipeline errors specifically
set -o pipefail
false | true | echo "This won't execute"
# Exit status will be 1 (from false command)
Complex Pipeline Examples
# Process logs with error handling
set -euo pipefail
# This pipeline will fail if any command fails
process_logs() {
cat access.log | \
grep -v "healthcheck" | \
awk '{print $1, $7}' | \
sort | \
uniq -c | \
sort -nr > top_ips.txt
}
if process_logs; then
echo "Log processing completed successfully"
else
echo "Error processing logs"
exit 1
fi
Practical Examples
System Administration
Safe System Administration Script
#!/bin/bash
# Safe system administration with strict error handling
# Enable strict mode
set -euo pipefail
IFS=$'\n\t'
# Enable debugging if requested
if [[ "${DEBUG:-0}" == "1" ]]; then
set -x
fi
# Variables with defaults
BACKUP_DIR="${BACKUP_DIR:-/backup}"
MAX_BACKUPS="${MAX_BACKUPS:-7}"
LOG_FILE="${LOG_FILE:-/var/log/backup.log}"
# Function to log messages
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
# Backup function with error handling
perform_backup() {
local source_dir="$1"
local backup_name="backup_$(date +%Y%m%d_%H%M%S).tar.gz"
log_message "Starting backup of $source_dir"
# This will fail if any command in pipeline fails
if tar -czf "$BACKUP_DIR/$backup_name" "$source_dir" 2>&1 | \
tee -a "$LOG_FILE"; then
log_message "Backup completed: $backup_name"
# Clean old backups
cd "$BACKUP_DIR"
ls -t backup_*.tar.gz | tail -n +$((MAX_BACKUPS + 1)) | xargs -r rm
else
log_message "ERROR: Backup failed for $source_dir"
return 1
fi
}
# Main execution
main() {
log_message "Backup script started"
# Check backup directory
if [[ ! -d "$BACKUP_DIR" ]]; then
log_message "Creating backup directory: $BACKUP_DIR"
mkdir -p "$BACKUP_DIR"
fi
# Perform backups
for dir in /home /etc /var/www; do
if [[ -d "$dir" ]]; then
perform_backup "$dir" || {
log_message "CRITICAL: Backup failed for $dir"
exit 1
}
fi
done
log_message "All backups completed successfully"
}
# Execute main function
main "$@"
Configuration Management
#!/bin/bash
# Configuration validation script
set -euo pipefail
# Configuration file path
CONFIG_FILE="${CONFIG_FILE:-/etc/myapp/config.yaml}"
# Function to validate configuration
validate_config() {
local file="$1"
echo "Validating configuration file: $file"
# Check if file exists
if [[ ! -f "$file" ]]; then
echo "ERROR: Configuration file not found: $file"
return 1
fi
# Check syntax (using yq for YAML validation)
if command -v yq >/dev/null 2>&1; then
if ! yq eval '.' "$file" >/dev/null 2>&1; then
echo "ERROR: Invalid YAML syntax in $file"
return 1
fi
fi
# Check required sections
local required_sections=("database" "server" "logging")
for section in "${required_sections[@]}"; do
if ! grep -q "^$section:" "$file"; then
echo "WARNING: Missing section: $section"
fi
done
echo "Configuration validation completed"
return 0
}
# Function to load configuration
load_config() {
local file="$1"
# Export configuration variables
set -a
# Source configuration if it's a shell script
if [[ "$file" == *.sh ]]; then
source "$file"
fi
set +a
}
# Main execution
if validate_config "$CONFIG_FILE"; then
load_config "$CONFIG_FILE"
echo "Configuration loaded successfully"
else
echo "ERROR: Configuration validation failed"
exit 1
fi
Development Workflow
Build Script with Error Handling
#!/bin/bash
# Build script with comprehensive error handling
set -euo pipefail
# Build configuration
BUILD_DIR="${BUILD_DIR:-build}"
SOURCE_DIR="${SOURCE_DIR:-src}"
CFLAGS="${CFLAGS:-Wall -Wextra -O2}"
MAKE_JOBS="${MAKE_JOBS:-$(nproc)}"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $*"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $*"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $*" >&2
}
# Clean function
clean_build() {
log_info "Cleaning build directory"
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
}
# Compile function
compile_project() {
log_info "Compiling project with $MAKE_JOBS jobs"
# This will fail if compilation fails
if make -j"$MAKE_JOBS" CFLAGS="$CFLAGS" all 2>&1 | \
tee build.log; then
log_info "Compilation successful"
else
log_error "Compilation failed. Check build.log for details."
return 1
fi
}
# Test function
run_tests() {
log_info "Running tests"
if [[ -d "tests" ]]; then
# This will fail if any test fails
if make test 2>&1 | tee test.log; then
log_info "All tests passed"
else
log_error "Tests failed. Check test.log for details."
return 1
fi
else
log_warn "No tests directory found, skipping tests"
fi
}
# Package function
package_build() {
log_info "Creating package"
local package_name="myapp-$(git describe --tags --always)-$(git rev-parse --short HEAD)"
if tar -czf "${package_name}.tar.gz" -C "$BUILD_DIR" .; then
log_info "Package created: ${package_name}.tar.gz"
else
log_error "Package creation failed"
return 1
fi
}
# Main build process
main() {
log_info "Starting build process"
# Parse command line arguments
case "${1:-all}" in
clean)
clean_build
;;
compile)
clean_build
compile_project
;;
test)
compile_project
run_tests
;;
package)
compile_project
run_tests
package_build
;;
all)
clean_build
compile_project
run_tests
package_build
;;
*)
echo "Usage: $0 {clean|compile|test|package|all}"
exit 1
;;
esac
log_info "Build process completed successfully"
}
# Execute main function
main "$@"
Development Environment Setup
#!/bin/bash
# Development environment setup script
set -euo pipefail
# Configuration
PROJECT_NAME="${PROJECT_NAME:-myproject}"
PYTHON_VERSION="${PYTHON_VERSION:-3.9}"
NODE_VERSION="${NODE_VERSION:-16}"
VENV_NAME="${VENV_NAME:-${PROJECT_NAME}_venv}"
# Function to check command availability
check_command() {
if command -v "$1" >/dev/null 2>&1; then
echo "✓ $1 is available"
return 0
else
echo "✗ $1 is not available"
return 1
fi
}
# Function to install dependencies
install_dependencies() {
echo "Installing system dependencies..."
# Update package list
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y python3 python3-pip nodejs npm build-essential
elif command -v yum >/dev/null 2>&1; then
sudo yum update -y
sudo yum install -y python3 python3-pip nodejs npm gcc make
else
echo "Unsupported package manager"
return 1
fi
}
# Function to setup Python environment
setup_python() {
echo "Setting up Python environment..."
# Create virtual environment
python3 -m venv "$VENV_NAME"
# Activate virtual environment
source "$VENV_NAME/bin/activate"
# Upgrade pip
pip install --upgrade pip
# Install requirements if file exists
if [[ -f "requirements.txt" ]]; then
pip install -r requirements.txt
fi
# Install development dependencies
pip install pytest black flake8 mypy pre-commit
}
# Function to setup Node.js environment
setup_nodejs() {
echo "Setting up Node.js environment..."
# Install npm dependencies if package.json exists
if [[ -f "package.json" ]]; then
npm install
fi
# Install development dependencies
npm install --save-dev eslint prettier jest
}
# Function to setup git hooks
setup_git_hooks() {
echo "Setting up git hooks..."
# Initialize pre-commit
pre-commit install
# Create pre-commit config if not exists
if [[ ! -f ".pre-commit-config.yaml" ]]; then
cat > .pre-commit-config.yaml << 'EOF'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
EOF
fi
}
# Function to create project structure
create_project_structure() {
echo "Creating project structure..."
mkdir -p src tests docs scripts
touch README.md .gitignore
# Create basic gitignore
cat > .gitignore << 'EOF'
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Virtual environments
venv/
env/
ENV/
# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
EOF
}
# Main setup function
main() {
echo "Setting up development environment for $PROJECT_NAME"
# Check prerequisites
local missing_commands=()
for cmd in git python3 npm; do
if ! check_command "$cmd"; then
missing_commands+=("$cmd")
fi
done
if [[ ${#missing_commands[@]} -gt 0 ]]; then
echo "Missing dependencies: ${missing_commands[*]}"
echo "Installing missing dependencies..."
install_dependencies
fi
# Create project structure
create_project_structure
# Setup Python environment
setup_python
# Setup Node.js environment (optional)
if [[ -f "package.json" ]] || [[ "${SETUP_NODE:-0}" == "1" ]]; then
setup_nodejs
fi
# Setup git hooks
setup_git_hooks
# Setup environment file
if [[ ! -f ".env" ]]; then
cat > .env << EOF
# Environment variables
PROJECT_NAME=$PROJECT_NAME
ENVIRONMENT=development
DEBUG=1
EOF
echo "Created .env file"
fi
echo ""
echo "Development environment setup completed!"
echo ""
echo "To start developing:"
echo "1. Activate virtual environment: source $VENV_NAME/bin/activate"
echo "2. Install dependencies: pip install -r requirements.txt"
echo "3. Start coding in the src/ directory"
echo "4. Run tests: pytest tests/"
echo ""
}
# Execute main function
main "$@"
Advanced Usage
Shell Option Combinations
Production Script Best Practices
#!/bin/bash
# Production script with strict error handling
# Set strict mode
set -euo pipefail
# Set secure IFS (prevent word splitting issues)
IFS=$'\n\t'
# Set secure umask
umask 077
# Trap cleanup on exit
cleanup() {
local exit_code=$?
echo "Script exiting with code: $exit_code"
# Cleanup operations here
rm -f /tmp/script_temp_*
}
trap cleanup EXIT
# Disable history expansion for security
set +H
# Your script logic here
echo "Running production script..."
Debugging Combinations
#!/bin/bash
# Development debugging script
# Enable all debugging options
set -xv # Show commands and input
# Enable error handling for debugging
set -euo pipefail
# Function to debug variables
debug_vars() {
echo "=== Variable Debug Info ==="
echo "Script name: $0"
echo "Arguments: $*"
echo "Argument count: $#"
echo "Current directory: $(pwd)"
echo "User: $(whoami)"
echo "Shell: $SHELL"
echo "PID: $$"
echo "=== Environment Variables ==="
env | sort
echo "========================="
}
# Debug function calls with set -x
debug_function() {
echo "Entering debug_function with args: $*"
local arg1="$1"
echo "Processing arg1: $arg1"
echo "Exiting debug_function"
}
# Call debug function
debug_vars "$@"
debug_function "test_argument"
Custom Error Handling
Advanced Error Handling with set -e
#!/bin/bash
# Advanced error handling
set -euo pipefail
# Custom error handler
error_handler() {
local line_number=$1
local exit_code=$2
echo "Error occurred in script at line $line_number"
echo "Exit code: $exit_code"
echo "Command: $BASH_COMMAND"
# Custom error recovery logic
if [[ $exit_code -eq 127 ]]; then
echo "Command not found error"
elif [[ $exit_code -eq 1 ]]; then
echo "General error"
fi
exit $exit_code
}
# Set up error trap
trap 'error_handler ${LINENO} $?' ERR
# Function with error handling
safe_operation() {
local operation="$1"
local file="$2"
echo "Performing operation: $operation on $file"
case "$operation" in
"read")
if [[ -r "$file" ]]; then
cat "$file"
else
echo "Cannot read file: $file" >&2
return 1
fi
;;
"write")
if [[ -w "$(dirname "$file")" ]]; then
echo "data" > "$file"
else
echo "Cannot write to file: $file" >&2
return 1
fi
;;
*)
echo "Unknown operation: $operation" >&2
return 1
;;
esac
}
# Test operations
safe_operation "read" "/etc/passwd"
safe_operation "write" "/tmp/test_file"
safe_operation "invalid" "test" # This will trigger error handler
Conditional Error Handling
#!/bin/bash
# Conditional error handling
# Function to enable/disable error handling based on context
set_error_handling() {
local mode="$1"
case "$mode" in
"strict")
set -euo pipefail
echo "Enabled strict error handling"
;;
"lenient")
set +euo pipefail
echo "Enabled lenient error handling"
;;
"debug")
set -euxo pipefail
echo "Enabled debug error handling"
;;
*)
echo "Unknown error handling mode: $mode"
return 1
;;
esac
}
# Example usage
echo "Starting with strict error handling"
set_error_handling "strict"
# This will fail in strict mode
# cat nonexistent_file.txt
echo "Switching to lenient error handling"
set_error_handling "lenient"
# This will not cause script exit
cat nonexistent_file.txt || echo "File not found, continuing..."
echo "Switching back to strict error handling"
set_error_handling "strict"
Integration and Automation
Shell Function Libraries
Utility Functions with set Options
#!/bin/bash
# Utility library with error handling
# Save original shell options
ORIGINAL_OPTS=$-
# Function to set temporary options
temp_set_options() {
local options="$1"
set $options
}
# Function to restore original options
restore_options() {
set -$ORIGINAL_OPTS
}
# Logging function with error handling
log_with_level() {
local level="$1"
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Temporarily disable exit on error for logging
temp_set_options "+e"
case "$level" in
"ERROR")
echo "[$timestamp] [ERROR] $message" >&2
;;
"WARN")
echo "[$timestamp] [WARN] $message" >&2
;;
"INFO")
echo "[$timestamp] [INFO] $message"
;;
*)
echo "[$timestamp] [DEBUG] $message"
;;
esac
# Restore original options
restore_options
}
# Safe file operation
safe_file_operation() {
local operation="$1"
local file="$2"
local temp_file="${file}.tmp.$$"
case "$operation" in
"atomic_write")
# Write to temp file first, then move atomically
if echo "$3" > "$temp_file" && mv "$temp_file" "$file"; then
log_with_level "INFO" "Successfully wrote to $file"
return 0
else
log_with_level "ERROR" "Failed to write to $file"
rm -f "$temp_file"
return 1
fi
;;
"backup_read")
# Create backup before reading
if [[ -f "$file" ]]; then
cp "$file" "${file}.backup.$$"
log_with_level "INFO" "Created backup of $file"
fi
cat "$file"
;;
esac
}
Configuration Management Scripts
Dynamic Configuration Loader
#!/bin/bash
# Dynamic configuration loader with set options
# Save current shell state
SAVE_STATE=$(set +o)
# Enable safe mode for configuration loading
set -euo pipefail
# Configuration directories
CONFIG_DIRS=(
"/etc/myapp"
"$HOME/.config/myapp"
"./config"
)
# Function to load configuration files
load_configuration() {
local config_name="$1"
local loaded_files=()
log_with_level "INFO" "Loading configuration: $config_name"
# Search for configuration files in priority order
for config_dir in "${CONFIG_DIRS[@]}"; do
local config_file="$config_dir/${config_name}.conf"
if [[ -f "$config_file" ]]; then
log_with_level "INFO" "Loading: $config_file"
# Temporarily disable nounset for configuration loading
temp_set_options "+u"
# Source configuration file with error handling
if source "$config_file"; then
loaded_files+=("$config_file")
log_with_level "INFO" "Successfully loaded: $config_file"
else
log_with_level "ERROR" "Failed to load: $config_file"
restore_options
return 1
fi
# Restore options
restore_options
fi
done
if [[ ${#loaded_files[@]} -eq 0 ]]; then
log_with_level "WARN" "No configuration files found for: $config_name"
else
log_with_level "INFO" "Loaded ${#loaded_files[@]} configuration file(s)"
fi
return 0
}
# Function to validate configuration
validate_configuration() {
local required_vars=("$@")
local missing_vars=()
for var in "${required_vars[@]}"; do
if [[ -z "${!var:-}" ]]; then
missing_vars+=("$var")
fi
done
if [[ ${#missing_vars[@]} -gt 0 ]]; then
log_with_level "ERROR" "Missing required variables: ${missing_vars[*]}"
return 1
fi
return 0
}
# Restore original shell state
eval "$SAVE_STATE"
Troubleshooting
Common Issues
Debugging Shell Option Problems
#!/bin/bash
# Debug shell option issues
# Function to show current shell state
debug_shell_state() {
echo "=== Shell Debug Information ==="
echo "Current shell options: $-"
echo "Current shell: $SHELL"
echo "Shell version: $BASH_VERSION"
echo "PID: $$"
echo "PPID: $PPID"
echo "Current directory: $(pwd)"
echo "Environment variables count: $(env | wc -l)"
echo "Positional parameters: $#"
echo "Positional parameters content: $*"
echo "============================="
}
# Function to test option combinations
test_option_combinations() {
echo "Testing option combinations..."
# Save original options
local original_opts=$-
# Test each option individually
for opt in e u x v f C m; do
echo "Testing option -$opt:"
set -$opt
echo " Options after set -$opt: $-"
# Test the option effect
case $opt in
e)
echo " Exit on error: $([[ $- == *e* ]] && echo "enabled" || echo "disabled")"
;;
u)
echo " Nounset: $([[ $- == *u* ]] && echo "enabled" || echo "disabled")"
;;
x)
echo " Xtrace: $([[ $- == *x* ]] && echo "enabled" || echo "disabled")"
;;
esac
# Restore and continue
set +$opt
done
# Restore original options
set -$original_opts
echo "Restored options: $-"
}
# Function to diagnose pipeline issues
diagnose_pipeline() {
echo "Diagnosing pipeline behavior..."
# Test pipeline with pipefail
echo "Testing with pipefail enabled:"
set -o pipefail
false | true
echo " Exit status after 'false | true': $?"
false | false
echo " Exit status after 'false | false': $?"
true | false
echo " Exit status after 'true | false': $?"
# Test without pipefail
echo "Testing without pipefail:"
set +o pipefail
false | true
echo " Exit status after 'false | true': $?"
false | false
echo " Exit status after 'false | false': $?"
}
# Run diagnostics
debug_shell_state
test_option_combinations
diagnose_pipeline
Variable Scope and Export Issues
#!/bin/bash
# Debug variable scope and export issues
# Function to test variable behavior with different set options
test_variable_behavior() {
echo "Testing variable behavior..."
# Test with nounset enabled
echo "Testing with nounset (-u):"
set -u
# This will fail
# echo "$UNSET_VAR"
# Provide default to avoid failure
echo "Default test: ${UNSET_VAR:-default_value}"
# Test with allexport
echo "Testing with allexport (-a):"
set -a
LOCAL_VAR="local_value"
set +a
# Test in subshell
echo "Testing in subshell:"
(
echo "In subshell, LOCAL_VAR: ${LOCAL_VAR:-not_set}"
)
echo "Back in parent, LOCAL_VAR: ${LOCAL_VAR:-not_set}"
# Reset options
set +u
}
# Function to test positional parameters
test_positional_parameters() {
echo "Testing positional parameters..."
# Set test parameters
set -- "arg1" "arg2 with spaces" "arg3"
echo "Number of parameters: $#"
echo "All parameters (\$@): $@"
echo "All parameters (\$*): $*"
echo "First parameter: $1"
echo "Second parameter: $2"
echo "Third parameter: $3"
# Test parameter expansion
echo "Testing parameter expansion:"
for i in {1..3}; do
echo "Parameter $i: ${!i}"
done
# Test shift
echo "After shift:"
shift
echo "Number of parameters: $#"
echo "Parameters: $@"
}
test_variable_behavior
test_positional_parameters
Performance Issues
#!/bin/bash
# Diagnose performance issues with shell options
# Function to benchmark operations with different options
benchmark_operations() {
local iterations=1000
echo "Benchmarking shell operations with $iterations iterations"
# Test without any options
echo "Testing without options:"
time for ((i=1; i<=iterations; i++)); do
dummy_var="test_value_$i"
done
# Test with xtrace enabled
echo "Testing with xtrace (-x):"
(
set -x
time for ((i=1; i<=iterations; i++)); do
dummy_var="test_value_$i"
done >/dev/null 2>&1
)
# Test with verbose enabled
echo "Testing with verbose (-v):"
(
set -v
time for ((i=1; i<=iterations; i++)); do
dummy_var="test_value_$i"
done >/dev/null 2>&1
)
# Test with noglob enabled
echo "Testing with noglob (-f):"
(
set -f
time for ((i=1; i<=iterations; i++)); do
dummy_var="test_value_$i"
done
)
}
# Function to test memory usage with different options
test_memory_usage() {
echo "Testing memory usage with different shell options"
# Function to create many variables
create_variables() {
local count=10000
for ((i=1; i<=count; i++)); do
declare "var_$i=value_$i"
done
echo "Created $count variables"
# Clean up
for ((i=1; i<=count; i++)); do
unset "var_$i"
done
}
# Test with allexport
echo "Testing with allexport enabled:"
(
set -a
/usr/bin/time -v create_variables 2>&1 | grep "Maximum resident"
)
# Test without allexport
echo "Testing without allexport:"
(
set +a
/usr/bin/time -v create_variables 2>&1 | grep "Maximum resident"
)
}
# Run benchmarks if time command is available
if command -v /usr/bin/time >/dev/null 2>&1; then
benchmark_operations
test_memory_usage
else
echo "GNU time command not available, skipping benchmarks"
fi
Related Commands
export- Set environment variables and mark them for exportunset- Remove variables or function definitionsdeclare- Declare variables and give them attributeslocal- Create local variables in functionsreadonly- Mark variables as unchangeableenv- Run a command in a modified environmentprintenv- Print all or part of the environmentshopt- Set and unset shell optionsulimit- Control resource limitsalias- Create and display command aliases
Best Practices
- Use strict mode (
set -euo pipefail) in production scripts for better error handling - Set IFS properly (
IFS=$'\n\t') to prevent word splitting issues - Use set -x for debugging complex scripts, but disable in production
- Enable set -u to catch undefined variable usage early
- Use set -o pipefail for reliable pipeline error detection
- Set set -C to prevent accidental file overwrites
- Save and restore shell options when temporarily changing them
- Use set -a for automatic variable export in configuration scripts
- Enable set -f when processing untrusted input to prevent glob expansion
- Test option combinations in development to ensure they work as expected
Performance Tips
- Avoid set -x in production as it significantly slows down script execution
- Use set +e selectively only when you need to handle specific errors
- Minimize set -u overhead by providing default values for optional variables
- Disable set -o pipefail only when you specifically need to ignore pipeline failures
- Use set -f when processing large amounts of data to avoid glob expansion overhead
- Test performance impact of different option combinations in your specific use case
- Consider using shopt for shell-specific options when appropriate
- Profile your scripts with and without debugging options to measure performance impact
The set command is a fundamental shell builtin that provides powerful control over shell behavior, error handling, and debugging capabilities. Mastering its various options and combinations is essential for writing robust, maintainable shell scripts and for effective shell administration.