Quiz 2
Registry Synced

Advanced Shell Scripting

1025 words
5 min read

Reading compass

Now · 🎯 Learning Objectives

Advanced Shell Scripting

🎯 Learning Objectives

  • Use arrays and associative arrays in bash
  • Perform string manipulation
  • Debug shell scripts effectively
  • Handle errors robustly
  • Parse command-line options with getopts
  • Use advanced I/O and process substitution

1. Arrays and Associative Arrays

bash
#!/bin/bash
# Indexed arrays
fruits=("apple" "banana" "cherry")
fruits[3]="date"                    # Add element
echo ${fruits[0]}                   # apple
echo ${fruits[@]}                   # All elements
echo ${#fruits[@]}                  # Length (4)
echo ${!fruits[@]}                  # Indices (0 1 2 3)
# Loop with index
for i in "${!fruits[@]}"; do
    echo "Index $i: ${fruits[$i]}"
done
# Associative arrays (bash 4+)
declare -A capitals
capitals=([India]="New Delhi" [USA]="Washington" [UK]="London")
echo ${capitals[India]}             # New Delhi
echo ${!capitals[@]}                # All keys
echo ${capitals[@]}                 # All values
for country in "${!capitals[@]}"; do
    echo "$country: ${capitals[$country]}"
done

2. String Manipulation

bash
#!/bin/bash
text="Hello World from Bash"
# Length
echo ${#text}                       # 19
# Substring
echo ${text:6}                      # World from Bash (from index 6)
echo ${text:6:5}                    # World (5 chars from index 6)
# Pattern removal (prefix)
echo ${text#Hello*}                 # Remove shortest "Hello*" prefix
echo ${text##* }                    # Remove longest " *" prefix → "Bash"
# Pattern removal (suffix)
echo ${text% *}                     # Remove shortest " *" suffix → "Hello World from"
echo ${text%% *}                    # Remove longest " *" suffix → "Hello"
# Search and replace
echo ${text/World/Earth}            # Replace first: "Hello Earth from Bash"
echo ${text// /_}                   # Replace all spaces: "Hello_World_from_Bash"
echo ${text/#Hello/Hi}              # Replace at start
echo ${text/%Bash/sh}               # Replace at end
# Case conversion
echo ${text,,}                      # Lowercase: "hello world from bash"
echo ${text^^}                      # Uppercase: "HELLO WORLD FROM BASH"
echo ${text,}                       # First char lowercase
echo ${text^}                       # First char uppercase
# Default values
name=${1:-"Guest"}                  # Use $1 or default "Guest"
file=${name:?Error: name required}  # Exit with error if empty

3. Debugging Scripts

bash
#!/bin/bash
# Debugging methods:
# 1. Shebang flags
#!/bin/bash -x                    # Print commands and their arguments
# 2. Set options in script
set -x                             # Enable debug (print commands)
set +x                             # Disable debug
set -v                             # Print shell input lines as read
set -n                             # Read commands but don't execute (syntax check)
# 3. Selective debugging
set -x                             # Start debugging
# ... commands to debug ...
set +x                             # Stop debugging
# 4. Verbose debugging
PS4='+ $BASH_SOURCE:$LINENO: $0: '  # Customize debug prompt
set -x
# 5. Check syntax without running
# bash -n script.sh                # Syntax check only
# 6. Trace execution
# bash -x script.sh                # Full trace
# bash -vx script.sh               # Verbose + trace

4. Error Handling

bash
#!/bin/bash
# Strict mode
set -euo pipefail                  # Exit on error, undefined vars, pipe fails
# Custom error handler
error_handler() {
    local line=$1
    local command=$2
    echo "Error on line $line: command '$command' failed"
    exit 1
}
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
# Check command success
if command_not_found; then
    echo "Success"
else
    echo "Failed with code: $?"
fi
# Retry logic
max_retries=3
retry_count=0
until [ $retry_count -ge $max_retries ]; do
    if curl -s https://api.example.com > /dev/null; then
        echo "Success"
        break
    fi
    ((retry_count++))
    echo "Retry $retry_count/$max_retries..."
    sleep 2
done

5. Command-Line Options with getopts

bash
#!/bin/bash
usage() {
    echo "Usage: $0 [-n name] [-a age] [-h]"
    exit 1
}
name=""
age=0
while getopts ":n:a:h" opt; do
    case $opt in
        n)
            name="$OPTARG"
            ;;
        a)
            age="$OPTARG"
            ;;
        h)
            usage
            ;;
        \?)
            echo "Invalid option: -$OPTARG"
            usage
            ;;
        :)
            echo "Option -$OPTARG requires an argument."
            usage
            ;;
    esac
done
echo "Name: $name, Age: $age"
# Usage: ./script.sh -n Alice -a 25

6. Process Substitution

bash
# Process substitution — feed output of command as a file
# Compare two command outputs
diff <(ls /dir1) <(ls /dir2)
# Read from process
while read line; do
    echo "Line: $line"
done < <(grep "ERROR" log.txt)
# Multiple process substitutions
paste <(cut -f1 file1.txt) <(cut -f3 file2.txt)

7. Practice Questions

Q1: How do you declare an associative array in bash?
Answer: declare -A myarray then myarray=([key1]="value1" [key2]="value2"). Associative arrays require bash 4+. Access with ${myarray[key1]}. Q2: How do you remove the file extension from a filename?
Answer: ${filename%.*} removes the shortest suffix matching .*. Example: file="data.txt"; echo ${file%.*} → "data". For multiple extensions: ${file%%.*} removes longest suffix. Q3: What does set -e do and why use it?
Answer: set -e causes the script to exit immediately if any command returns a non-zero exit status. Combined with set -u (error on undefined variables) and set -o pipefail (fail if any command in pipe fails), it's called "strict mode" and prevents silent failures. Q4: How do you debug a bash script?
Answer: bash -x script.sh (trace mode), or add set -x in the script. bash -n script.sh checks syntax without executing. PS4='$LINENO: ' customizes the debug prompt to show line numbers. Q5: How do you parse command-line flags with getopts?
Answer:
bash
while getopts ":n:a:" opt; do
    case $opt in n) name="$OPTARG" ;; a) age="$OPTARG" ;; esac
done
The colon prefix (:) suppresses default error messages. $OPTARG gets the argument value. Q6: What is process substitution?
Answer: <(command) treats the output of a command as a file. Useful with commands that expect file arguments: diff <(cmd1) <(cmd2). Creates a named pipe or /dev/fd entry behind the scenes. Q7: How do you convert a string to uppercase in bash?
Answer: ${text^^} (uppercase all), ${text^} (first char uppercase), ${text,,} (lowercase all). These work in bash 4+. Q8: Write a function that validates a non-empty argument and returns an error if missing.
bash
require_arg() {
    if [ -z "$2" ]; then
        echo "Error: $1 is required"
        exit 1
    fi
}
require_arg "--name" "$name"

📐 Key Concepts

FeatureSyntaxPurpose
Arrayarr=(val1 val2)Indexed list
Assoc arraydeclare -A arrKey-value pairs
String length${#str}Character count
Substring${str:start:len}Extract part
Replace${str/old/new}Pattern replacement
Debugset -xTrace execution
Error traptrap ... ERRCatch errors
getoptswhile getoptsParse options
Process sub<(cmd)Output as file

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.