Shell

#9
GitHub#5
RedMonk#14
IEEESpectrum#14
JetBrains#7
scripting languagesystem administrationautomationDevOpscommand line

Scripting Language

Shell

Overview

Shell is a scripting language for command-line operations and automation scripts on Unix-like operating systems. It plays important roles in various scenarios including system administration, file operations, process control, and CI/CD pipelines. There are several types including Bash, Zsh, and Fish.

Details

The most common Bash (Bourne Again Shell) was developed in 1989 as part of the GNU project. It is widely adopted as the standard shell for Unix-like systems and is used on Linux, macOS, WSL, and other platforms.

Shell scripts can automate complex tasks using combinations of commands, conditional statements, loops, and functions. With the spread of DevOps, its importance has increased in Infrastructure as Code, CI/CD, and container management.

Code Examples

Hello World

#!/bin/bash
echo "Hello, World!"

Variables and Basic Operations

#!/bin/bash

# Variable definition
name="John"
age=25
current_date=$(date)

# Variable usage
echo "Name: $name"
echo "Age: ${age} years old"
echo "Current time: $current_date"

# Numeric calculation
x=10
y=5
sum=$((x + y))
echo "$x + $y = $sum"

# String manipulation
text="Hello World"
echo "Length: ${#text}"
echo "Uppercase: ${text^^}"
echo "Lowercase: ${text,,}"

Command Line Arguments and Conditionals

#!/bin/bash

# Check command line arguments
if [ $# -eq 0 ]; then
    echo "Usage: $0 <filename>"
    exit 1
fi

filename=$1

# Check file existence
if [ -f "$filename" ]; then
    echo "File '$filename' found"
    
    # Check file attributes
    if [ -r "$filename" ]; then
        echo "Readable"
    fi
    
    if [ -w "$filename" ]; then
        echo "Writable"
    fi
    
    if [ -x "$filename" ]; then
        echo "Executable"
    fi
    
    # Display file information
    echo "File size: $(stat -f%z "$filename" 2>/dev/null || stat -c%s "$filename" 2>/dev/null) bytes"
    echo "Last modified: $(stat -f%Sm "$filename" 2>/dev/null || stat -c%y "$filename" 2>/dev/null)"
    
elif [ -d "$filename" ]; then
    echo "'$filename' is a directory"
    echo "Number of files: $(ls -1 "$filename" | wc -l)"
else
    echo "File '$filename' not found"
    exit 1
fi

Loops and Arrays

#!/bin/bash

# Array definition
fruits=("apple" "banana" "orange" "grape")

# Display array (for loop)
echo "Fruit list:"
for fruit in "${fruits[@]}"; do
    echo "- $fruit"
done

# Loop with index
echo -e "\nNumbered list:"
for i in "${!fruits[@]}"; do
    echo "$((i+1)). ${fruits[i]}"
done

# While loop example
echo -e "\nNumbers 1 to 5:"
counter=1
while [ $counter -le 5 ]; do
    echo "Number: $counter"
    ((counter++))
done

# File processing loop
echo -e "\nText files in current directory:"
for file in *.txt; do
    if [ -f "$file" ]; then
        echo "Text file: $file"
    fi
done

Functions and Argument Processing

#!/bin/bash

# Simple function
greet() {
    local name=$1
    local time=$2
    echo "${time}, ${name}!"
}

# File backup function
backup_file() {
    local source_file=$1
    local backup_dir=$2
    
    # Argument check
    if [ $# -ne 2 ]; then
        echo "Usage: backup_file <source_file> <backup_directory>"
        return 1
    fi
    
    # Check source file existence
    if [ ! -f "$source_file" ]; then
        echo "Error: File '$source_file' not found"
        return 1
    fi
    
    # Create backup directory
    mkdir -p "$backup_dir"
    
    # Generate backup filename
    local filename=$(basename "$source_file")
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local backup_file="${backup_dir}/${filename}.backup.${timestamp}"
    
    # Copy file
    if cp "$source_file" "$backup_file"; then
        echo "Backup completed: $backup_file"
        return 0
    else
        echo "Error: Backup failed"
        return 1
    fi
}

# Function usage
greet "John" "Good morning"
greet "Jane" "Good evening"

# Test backup function
echo "sample.txt" > sample.txt
backup_file "sample.txt" "./backup"

System Administration Script

#!/bin/bash

# System information collection script
collect_system_info() {
    echo "=== System Information Report ==="
    echo "Generated: $(date)"
    echo ""
    
    # OS information
    echo "=== OS Information ==="
    if command -v lsb_release >/dev/null 2>&1; then
        lsb_release -a
    elif [ -f /etc/os-release ]; then
        cat /etc/os-release
    else
        uname -a
    fi
    echo ""
    
    # CPU information
    echo "=== CPU Information ==="
    if [ -f /proc/cpuinfo ]; then
        grep "model name" /proc/cpuinfo | head -1
        echo "CPU count: $(nproc)"
    fi
    echo ""
    
    # Memory information
    echo "=== Memory Information ==="
    if command -v free >/dev/null 2>&1; then
        free -h
    fi
    echo ""
    
    # Disk usage
    echo "=== Disk Usage ==="
    df -h
    echo ""
    
    # Process information (top 5 by CPU usage)
    echo "=== Top CPU Usage Processes ==="
    ps aux --sort=-%cpu | head -6
    echo ""
    
    # Network connections
    echo "=== Network Connections ==="
    if command -v ss >/dev/null 2>&1; then
        ss -tuln
    elif command -v netstat >/dev/null 2>&1; then
        netstat -tuln
    fi
}

# Log rotation function
rotate_logs() {
    local log_dir=$1
    local days_to_keep=$2
    
    if [ $# -ne 2 ]; then
        echo "Usage: rotate_logs <log_directory> <days_to_keep>"
        return 1
    fi
    
    echo "Starting log rotation: $log_dir"
    
    # Delete old log files
    find "$log_dir" -name "*.log" -type f -mtime +$days_to_keep -delete
    
    # Delete compressed log files too
    find "$log_dir" -name "*.log.gz" -type f -mtime +$days_to_keep -delete
    
    echo "Log rotation completed"
}

# Usage examples
collect_system_info > system_report_$(date +%Y%m%d).txt
rotate_logs "/var/log/myapp" 30

Error Handling and Debugging

#!/bin/bash

# Exit on error
set -e

# Exit on undefined variable usage
set -u

# Exit on first failure in pipeline
set -o pipefail

# Debug mode (display executed commands)
# set -x

# Error handling function
error_exit() {
    echo "Error: $1" >&2
    exit 1
}

# Cleanup function
cleanup() {
    echo "Running cleanup..."
    # Delete temporary files etc.
    rm -f /tmp/script_temp_*
}

# Signal handling (cleanup on script exit)
trap cleanup EXIT
trap 'error_exit "Script interrupted"' INT TERM

# File processing example
process_file() {
    local input_file=$1
    local output_file=$2
    
    # Check input file
    [ -f "$input_file" ] || error_exit "Input file not found: $input_file"
    
    # Create output directory
    local output_dir=$(dirname "$output_file")
    mkdir -p "$output_dir" || error_exit "Failed to create output directory: $output_dir"
    
    # Execute processing
    if ! grep -v "^#" "$input_file" > "$output_file"; then
        error_exit "File processing failed"
    fi
    
    echo "Processing completed: $output_file"
}

# Usage example
echo "Script started"
process_file "/etc/hosts" "/tmp/hosts_filtered.txt"
echo "Script completed successfully"

Advantages and Disadvantages

Advantages

  • System Integration: Direct integration with OS commands
  • Automation: Efficient automation of repetitive tasks
  • Lightweight: Available immediately without additional installation
  • DevOps Support: Standard tool for CI/CD and infrastructure management
  • Text Processing: Powerful text processing with pipes and redirection
  • Rich Commands: Wide range of processing possible with Unix tools

Disadvantages

  • Readability: Complex scripts are difficult to understand
  • Error Handling: Default error handling is insufficient
  • Portability: Differences between OS and shells
  • Debugging: Limited debugging tools
  • Large-scale Development: Unsuitable for large application development

Key Links

Ranking Information

  • Overall Ranking: 9th
  • GitHub Usage: 5th
  • RedMonk Language Ranking: 14th
  • IEEE Spectrum: 14th
  • JetBrains Developer Survey: 7th

Shell is an essential scripting language for system administration and DevOps, playing important roles in automation and system integration.