🐚 Bash Introduction

🎯 Complete Definition

Bash (Bourne Again SHell) is a Unix shell and command-line interpreter created by Brian Fox for the GNU Project as a free software replacement for the Bourne shell. It's the default shell on most Linux distributions and macOS, providing a powerful interface for interacting with the operating system, automating tasks, and writing scripts.

🔬 Core Characteristics

  • Command Interpretation: Executes user commands and system programs
  • Scripting Language: Complete programming language for automation
  • Job Control: Manage multiple processes (background, foreground, suspend)
  • I/O Redirection: Control input/output streams with operators
  • Pipelines: Chain commands together for complex operations
  • Wildcards/Globbing: Pattern matching for filenames
  • Command History: Recall and reuse previous commands
  • Command Aliases: Create shortcuts for frequently used commands
  • Environment Variables: Configure shell behavior and store data

📊 Industry Usage

Bash is ubiquitous in system administration, DevOps, cloud computing, and software development. Used for server management, deployment scripts, build automation, data processing pipelines, and development environment configuration. Essential for Linux/Unix administrators, developers, data scientists, and DevOps engineers.

#!/bin/bash # Bash Introduction - CodeOrbitPro echo "🐚 Welcome to Bash Pro Track!" # Basic commands echo "Current directory: $(pwd)" echo "Current user: $(whoami)" echo "System info: $(uname -a)" # Variables name="Bash" version="5.1" echo "Shell: $name, Version: $version" # Command substitution files=$(ls -la | wc -l) echo "Files in current directory: $files" # Simple calculation echo "5 + 3 = $((5 + 3))" # Conditionals if [ -f "$0" ]; then echo "This script exists!" fi # Loop echo "Counting to 5:" for i in {1..5}; do echo -n "$i " done echo "" # Exit status echo "Exit status of last command: $?"

📝 Basics & Syntax

🎯 Complete Definition

Bash syntax follows a specific structure with commands, options, arguments, and operators. Understanding the basic syntax is essential for writing effective shell scripts and using the command line efficiently.

📋 Key Elements

  • Shebang: #!/bin/bash - First line of script specifying interpreter
  • Commands: Built-ins (echo, cd) or external programs (ls, grep)
  • Options: Modify command behavior with - or -- (ls -la, grep -i)
  • Arguments: Inputs to commands (ls /home, echo "Hello")
  • Comments: # for single-line comments
  • Statement Termination: Newline or ; for multiple commands on one line
  • Command Separators: ; (sequential), && (AND), || (OR)
  • Line Continuation: \ at end of line for multi-line commands
  • Quoting: Single quotes (literal), double quotes (interpreted), backticks (command)

🔧 Special Characters

  • $ - Variable expansion, command substitution
  • # - Comment, number sign
  • * - Wildcard, multiplication
  • ? - Single character wildcard
  • [] - Character class, test command
  • {} - Brace expansion
  • () - Subshell, command grouping
  • | - Pipe
  • > - Redirect output
  • < - Redirect input
  • & - Background process
#!/bin/bash # Bash Basics & Syntax # Shebang line tells the system to use bash interpreter # Comments start with # # This is a comment and won't be executed # Basic command echo "Hello, World!" # Command with options ls -la # Command with arguments echo "Current user: $(whoami)" # Multiple commands on one line (using ;) echo "First"; echo "Second"; echo "Third" # Conditional execution (&& = AND, || = OR) true && echo "This runs" # Runs because true succeeds false || echo "This runs" # Runs because false fails # Command grouping { echo "Group"; echo "Commands"; } # Subshell (cd /tmp; pwd) # Changes to /tmp in subshell only pwd # Still in original directory # Line continuation (using \) echo "This is a very long line that \ continues on the next line" # Quoting examples name="World" echo 'Single quotes: $name' # Output: $name (literal) echo "Double quotes: $name" # Output: World (expanded) # Command substitution (old style with backticks) files=`ls` echo "Files: $files" # Command substitution (new style with $()) files=$(ls) echo "Files: $files" # Exit status ls /tmp echo "Exit status: $?" # 0 = success, non-zero = failure

🔤 Variables

🎯 Complete Definition

Bash variables are named storage locations that hold data. They are untyped (everything is a string) and can store text, numbers, filenames, or command output. Variables can be local to a script, exported to child processes, or special system-defined variables.

📋 Variable Types

  • User Variables: Created by user (name="John")
  • Environment Variables: Exported to child processes (PATH, HOME, USER)
  • Special/Positional Parameters: $0, $1, $2... (script arguments)
  • Special Variables: $?, $$, $!, $#, $@, $*
  • Readonly Variables: Cannot be changed after declaration
  • Array Variables: Store multiple values (indexed or associative)

🔧 Variable Operations

  • Assignment: name=value (no spaces around =)
  • Access: $name or ${name}
  • Unset: unset name
  • Export: export name (makes available to child processes)
  • Readonly: readonly name (prevents changes)
  • Default Values: ${var:-default}, ${var:=default}, ${var:?error}
  • String Operations: ${#var} (length), ${var:offset:length} (substring)
  • Pattern Removal: ${var#pattern}, ${var##pattern}, ${var%pattern}, ${var%%pattern}
  • Search/Replace: ${var/pattern/replacement}
#!/bin/bash # Variables in Bash # ===== USER VARIABLES ===== # Assignment (no spaces around =) name="John Doe" age=30 city="New York" # Access variables echo "Name: $name" echo "Age: $age" echo "City: ${city}" # Curly braces optional, but good practice # ===== ENVIRONMENT VARIABLES ===== echo "Home directory: $HOME" echo "Current user: $USER" echo "Path: $PATH" echo "Shell: $SHELL" echo "Current directory: $PWD" # Export variables to child processes export MY_VAR="Hello from parent" bash -c 'echo "Child process: $MY_VAR"' # ===== SPECIAL VARIABLES ===== echo "Script name: $0" echo "Number of arguments: $#" echo "All arguments as string: $*" echo "All arguments as array: $@" echo "Process ID of this script: $$" echo "Exit status of last command: $?" # ===== VARIABLE EXPANSION TRICKS ===== # Default values unset myvar echo "Default: ${myvar:-default}" # Prints "default", myvar unchanged echo "Assign default: ${myvar:=default}" # Sets myvar to "default" echo "Now myvar = $myvar" # Error if unset # echo "${myvar:?Error: myvar not set}" # Prints error and exits # ===== STRING OPERATIONS ===== text="Hello World Bash Scripting" echo "Length: ${#text}" echo "Substring (0-5): ${text:0:5}" echo "Substring (6-5): ${text:6:5}" echo "Substring from 6: ${text:6}" # ===== PATTERN REMOVAL ===== filename="archive.tar.gz" echo "Remove shortest from front: ${filename#*.}" # tar.gz echo "Remove longest from front: ${filename##*.}" # gz echo "Remove shortest from back: ${filename%.*}" # archive.tar echo "Remove longest from back: ${filename%%.*}" # archive # ===== SEARCH AND REPLACE ===== message="The quick brown fox jumps over the lazy dog" echo "Replace first 'the' with 'a': ${message/the/a}" echo "Replace all 'o' with '0': ${message//o/0}" echo "Replace prefix: ${message/#The/A}" echo "Replace suffix: ${message/%dog/cat}" # ===== READONLY VARIABLES ===== readonly PI=3.14159 # PI=3.14 # This would cause an error # ===== UNSET VARIABLES ===== temp_var="temporary" unset temp_var echo "temp_var after unset: $temp_var" # Empty

🧮 Operators

🎯 Complete Definition

Bash operators perform operations on variables and values. They include arithmetic operators, comparison operators, logical operators, file test operators, and string test operators. Understanding operators is crucial for creating conditional logic in scripts.

📊 Arithmetic Operators

  • + - Addition
  • - - Subtraction
  • * - Multiplication
  • / - Division (integer division)
  • % - Modulus (remainder)
  • ** - Exponentiation
  • += -= *= /= - Assignment operators
  • ++ -- - Increment/Decrement

🔍 Comparison Operators

  • Numeric: -eq, -ne, -lt, -le, -gt, -ge
  • String: =, ==, !=, <, > (in [[ ]])
  • String tests: -z (empty), -n (non-empty)

🔗 Logical Operators

  • && - Logical AND
  • || - Logical OR
  • ! - Logical NOT

📁 File Test Operators

  • -e - File exists
  • -f - Regular file
  • -d - Directory
  • -r - Readable
  • -w - Writable
  • -x - Executable
  • -s - Size > 0
  • -L - Symbolic link
  • -nt - Newer than
  • -ot - Older than
#!/bin/bash # Operators in Bash # ===== ARITHMETIC OPERATORS ===== # Using $((...)) for arithmetic a=10 b=3 echo "a = $a, b = $b" echo "Addition: a + b = $((a + b))" echo "Subtraction: a - b = $((a - b))" echo "Multiplication: a * b = $((a * b))" echo "Division: a / b = $((a / b))" # Integer division echo "Modulus: a % b = $((a % b))" echo "Exponentiation: a ** b = $((a ** b))" # Increment/Decrement c=5 echo "c = $c" echo "c++ = $((c++))" # Post-increment echo "Now c = $c" echo "++c = $((++c))" # Pre-increment echo "Now c = $c" # Assignment operators d=10 echo "d = $d" ((d += 5)) echo "d += 5 => $d" ((d *= 2)) echo "d *= 2 => $d" # Using let for arithmetic let "e = 5 + 3" echo "let e = 5 + 3 => $e" let e++ echo "let e++ => $e" # Using expr (older method) f=$(expr 10 + 5) echo "expr 10 + 5 => $f" # ===== NUMERIC COMPARISONS ===== # Use with test command [ ] or [[ ]] x=10 y=20 if [ $x -eq $y ]; then echo "$x equals $y"; fi if [ $x -ne $y ]; then echo "$x not equals $y"; fi if [ $x -lt $y ]; then echo "$x less than $y"; fi if [ $x -le $y ]; then echo "$x less or equal $y"; fi if [ $x -gt $y ]; then echo "$x greater than $y"; fi if [ $x -ge $y ]; then echo "$x greater or equal $y"; fi # Using [[ ]] (bash-specific, more features) if [[ $x -lt $y ]]; then echo "[[ $x -lt $y ]] is true" fi # ===== STRING COMPARISONS ===== str1="hello" str2="world" str3="hello" if [ "$str1" = "$str3" ]; then echo "Strings are equal (with =)" fi if [[ "$str1" == "$str3" ]]; then echo "Strings are equal (with == in [[ ]])" fi if [ "$str1" != "$str2" ]; then echo "Strings are different" fi # String comparison (alphabetical) if [[ "$str1" < "$str2" ]]; then echo "'$str1' comes before '$str2'" fi # String empty checks empty="" if [ -z "$empty" ]; then echo "String is empty (-z)" fi not_empty="text" if [ -n "$not_empty" ]; then echo "String is not empty (-n)" fi # ===== LOGICAL OPERATORS ===== # && (AND), || (OR), ! (NOT) a=5 b=10 c=15 if [ $a -lt $b ] && [ $b -lt $c ]; then echo "Both conditions true (&&)" fi if [ $a -gt $b ] || [ $b -lt $c ]; then echo "At least one condition true (||)" fi if ! [ $a -gt $b ]; then echo "NOT condition (!)" fi # Using [[ ]] with && and || if [[ $a -lt $b && $b -lt $c ]]; then echo "Using && inside [[ ]]" fi if [[ $a -gt $b || $b -lt $c ]]; then echo "Using || inside [[ ]]" fi # ===== FILE TEST OPERATORS ===== file="/etc/passwd" dir="/tmp" link="/usr/bin/bash" if [ -e "$file" ]; then echo "File exists (-e)"; fi if [ -f "$file" ]; then echo "Regular file (-f)"; fi if [ -d "$dir" ]; then echo "Directory (-d)"; fi if [ -r "$file" ]; then echo "File is readable (-r)"; fi if [ -w "$file" ]; then echo "File is writable (-w)"; fi if [ -x "$dir" ]; then echo "Directory is executable/searchable (-x)"; fi if [ -s "$file" ]; then echo "File size > 0 (-s)"; fi if [ -L "$link" ]; then echo "Symbolic link (-L)"; fi # File comparisons if [ "$file" -nt "$dir" ]; then echo "File is newer than directory" fi # ===== COMBINING TESTS ===== # Complex conditions if [ -f "$file" ] && [ -r "$file" ] && [ -s "$file" ]; then echo "File exists, is readable, and has content" fi if [[ -f "$file" && -r "$file" && -s "$file" ]]; then echo "Same check with [[ ]]" fi # ===== TERNARY-LIKE OPERATORS ===== # Using && and || for simple conditionals [[ $x -gt 5 ]] && echo "x > 5" || echo "x <= 5" # Using if-then-else (more readable) if [ $x -gt 5 ]; then echo "x > 5" else echo "x <= 5" fi

📋 Strings

🎯 Complete Definition

Strings in Bash are sequences of characters. Bash provides extensive string manipulation capabilities including concatenation, slicing, pattern matching, and various transformations. Understanding string handling is essential for text processing in shell scripts.

📋 String Operations

  • Concatenation: Just place strings/variables together: "Hello $name"
  • Length: ${#string}
  • Substring: ${string:position:length}
  • Pattern removal: ${string#pattern}, ${string##pattern}, ${string%pattern}, ${string%%pattern}
  • Search & replace: ${string/pattern/replacement}, ${string//pattern/replacement}
  • Case conversion: ${string^}, ${string^^}, ${string,}, ${string,,}
  • Trim whitespace: Using pattern removal or external tools
  • Split strings: Using IFS or read -a
  • Here documents: Multi-line strings with <
  • Here strings: <<< for feeding strings to commands

🔧 Quote Types

  • Single quotes (''): Preserve literal value of all characters
  • Double quotes (""): Allow variable expansion and command substitution
  • Backticks (``): Command substitution (old style)
  • $'' : ANSI-C quoting (supports escape sequences)
  • $"" : Localization quoting
#!/bin/bash # String Manipulation in Bash # ===== STRING CONCATENATION ===== first="Hello" second="World" space=" " result="$first$space$second" echo "Concatenated: $result" # Direct concatenation name="John" greeting="Hello, $name!" echo "$greeting" # ===== STRING LENGTH ===== text="Hello, Bash!" echo "Text: $text" echo "Length: ${#text}" # ===== SUBSTRING EXTRACTION ===== text="The quick brown fox" echo "Original: $text" echo "First 5 chars: ${text:0:5}" echo "Chars 4-8: ${text:4:5}" echo "From position 10: ${text:10}" echo "Last 3 chars: ${text: -3}" # Space needed before -3 # ===== PATTERN REMOVAL ===== url="https://www.example.com/page.html" file="archive.tar.gz" path="/home/user/docs/file.txt" echo "URL: $url" echo "Remove http://: ${url#http://}" echo "Remove up to first dot: ${url#*.}" echo "Remove up to last dot: ${url##*.}" echo "Remove domain: ${url##*/}" echo "File: $file" echo "Remove shortest suffix: ${file%.*}" # archive.tar echo "Remove longest suffix: ${file%%.*}" # archive echo "Remove shortest prefix: ${file#*.}" # tar.gz echo "Remove longest prefix: ${file##*.}" # gz echo "Path: $path" echo "Directory: ${path%/*}" # /home/user/docs echo "Filename: ${path##*/}" # file.txt # ===== SEARCH AND REPLACE ===== sentence="The cat sat on the mat" echo "Original: $sentence" echo "Replace first 'cat' with 'dog': ${sentence/cat/dog}" echo "Replace first 'at' with 'AT': ${sentence/at/AT}" echo "Replace all 'at' with 'AT': ${sentence//at/AT}" echo "Replace prefix 'The' with 'A': ${sentence/#The/A}" echo "Replace suffix 'mat' with 'rug': ${sentence/%mat/rug}" # ===== CASE CONVERSION ===== text="hello WORLD" echo "Original: $text" echo "First char uppercase: ${text^}" echo "All uppercase: ${text^^}" echo "First char lowercase: ${text,}" echo "All lowercase: ${text,,}" echo "Title case (each word):" for word in $text; do echo -n "${word^} " done echo "" # ===== STRING SPLITTING ===== # Using IFS data="apple,banana,orange,grape" IFS=',' read -ra fruits <<< "$data" echo "Split fruits:" for fruit in "${fruits[@]}"; do echo " - $fruit" done # Using read -a for word splitting sentence="This is a sample sentence" read -ra words <<< "$sentence" echo "Words: ${words[0]}, ${words[1]}, ${words[2]}" # ===== HERE DOCUMENTS ===== # Multi-line string with <

📊 Arrays

🎯 Complete Definition

Bash arrays are data structures that store multiple values under a single variable name. Bash supports both indexed arrays (with numeric indices) and associative arrays (with string keys). Arrays are powerful for managing collections of data in shell scripts.

📋 Array Types

  • Indexed Arrays: Numeric indices starting at 0 (default)
  • Associative Arrays: String keys (declare -A)

🔧 Array Operations

  • Declaration: array=(), declare -a array, declare -A assoc
  • Assignment: array[0]="value", array+=(element), array=(val1 val2)
  • Access: ${array[index]}
  • All elements: ${array[@]}, ${array[*]}
  • Indices: ${!array[@]}
  • Length: ${#array[@]}
  • Slicing: ${array[@]:start:count}
  • Delete element: unset array[index]
  • Delete array: unset array
#!/bin/bash # Arrays in Bash # ===== INDEXED ARRAYS ===== # Declaration methods fruits=("apple" "banana" "orange") # Explicit colors[0]="red" # Individual colors[1]="green" colors[2]="blue" declare -a numbers # Declare empty array numbers+=(1 2 3 4 5) # Append echo "Fruits: ${fruits[@]}" echo "Colors: ${colors[@]}" echo "Numbers: ${numbers[@]}" # ===== ACCESSING ARRAY ELEMENTS ===== echo "First fruit: ${fruits[0]}" echo "Second fruit: ${fruits[1]}" echo "Third fruit: ${fruits[2]}" # ===== ARRAY LENGTH ===== echo "Number of fruits: ${#fruits[@]}" echo "Length of first fruit: ${#fruits[0]}" # ===== ALL ELEMENTS ===== # Using @ (preserves word splitting) for fruit in "${fruits[@]}"; do echo "Fruit: $fruit" done # ===== ARRAY INDICES ===== echo "Indices of fruits: ${!fruits[@]}" # ===== APPENDING ELEMENTS ===== fruits+=("grape" "kiwi") echo "After append: ${fruits[@]}" # ===== REMOVING ELEMENTS ===== unset fruits[1] # Remove element at index 1 echo "After removing index 1: ${fruits[@]}" # ===== SLICING ARRAYS ===== numbers=(1 2 3 4 5 6 7 8 9 10) echo "First 3: ${numbers[@]:0:3}" echo "From index 4: ${numbers[@]:4}" echo "Last 3: ${numbers[@]: -3}" # ===== ASSOCIATIVE ARRAYS ===== # Must declare with -A declare -A user # Assign values user["name"]="John Doe" user["age"]=30 user["city"]="New York" user["email"]="john@example.com" # Access values echo "Name: ${user["name"]}" echo "Age: ${user["age"]}" echo "City: ${user["city"]}" # List all keys and values echo "All keys: ${!user[@]}" echo "All values: ${user[@]}" # Iterate over associative array for key in "${!user[@]}"; do echo "$key: ${user[$key]}" done # ===== ARRAY FROM COMMAND OUTPUT ===== # Split output into array mapfile -t files < <(ls -la) echo "Files in current directory: ${#files[@]}" echo "First 3 files:" for ((i=0; i<3 && i<${#files[@]}; i++)); do echo " ${files[$i]}" done # ===== PRACTICAL EXAMPLES ===== # 1. Parse CSV line csv_line="John,30,New York,Engineer" IFS=',' read -ra fields <<< "$csv_line" echo "CSV fields:" for i in "${!fields[@]}"; do echo " [$i]: ${fields[$i]}" done # 2. Unique values values=(apple banana apple orange banana grape) declare -A seen unique=() for value in "${values[@]}"; do if [[ -z "${seen[$value]}" ]]; then seen[$value]=1 unique+=("$value") fi done echo "Unique values: ${unique[@]}" # 3. Stack implementation stack=() push() { stack+=("$1") } pop() { if [ ${#stack[@]} -gt 0 ]; then local last_index=$((${#stack[@]} - 1)) local value="${stack[$last_index]}" unset 'stack[$last_index]' stack=("${stack[@]}") # Re-index echo "$value" fi } push "first" push "second" push "third" echo "Stack: ${stack[@]}" echo "Pop: $(pop)" echo "Stack now: ${stack[@]}"

🔄 Conditionals

🎯 Complete Definition

Conditionals in Bash allow scripts to make decisions based on conditions. They evaluate commands or test expressions and execute different code paths based on the result. Bash provides several conditional constructs including if, elif, else, case, and the test command.

📋 Conditional Constructs

  • if statement: Basic conditional branching
  • if-else: Two-way branching
  • if-elif-else: Multi-way branching
  • case statement: Pattern matching conditional
  • && and ||: Short-circuit conditionals
  • test command: [ ] or [[ ]] for evaluating conditions
  • Conditional expressions: (( )) for arithmetic conditions

🔧 Test Constructs

  • [ ] (single brackets): POSIX test command
  • [[ ]] (double brackets): Bash extended test (more features)
  • (( )) : Arithmetic evaluation
  • && and || : Command chaining based on success/failure
#!/bin/bash # Conditionals in Bash # ===== BASIC IF STATEMENT ===== if [ -f "/etc/passwd" ]; then echo "Password file exists" fi # ===== IF-ELSE STATEMENT ===== age=18 if [ $age -ge 18 ]; then echo "You are an adult" else echo "You are a minor" fi # ===== IF-ELIF-ELSE ===== score=85 if [ $score -ge 90 ]; then grade="A" elif [ $score -ge 80 ]; then grade="B" elif [ $score -ge 70 ]; then grade="C" elif [ $score -ge 60 ]; then grade="D" else grade="F" fi echo "Score: $score, Grade: $grade" # ===== USING DOUBLE BRACKETS [[ ]] ===== # [[ ]] has more features and is safer name="John Doe" if [[ $name =~ ^John ]]; then echo "Name starts with John" fi # Pattern matching in [[ ]] if [[ $name == *"Doe"* ]]; then echo "Name contains Doe" fi # Regular expressions phone="123-456-7890" if [[ $phone =~ ^[0-9]{3}-[0-9]{3}-[0-9]{4}$ ]]; then echo "Valid phone number format" fi # ===== ARITHMETIC CONDITIONS WITH (( )) ===== x=10 y=20 if (( x > 5 )); then echo "x is greater than 5" fi if (( x + y > 25 )); then echo "Sum is greater than 25" fi # ===== CASE STATEMENT ===== # Pattern matching for multi-way branching fruit="apple" case $fruit in "apple") echo "It's an apple" ;; "banana") echo "It's a banana" ;; "orange"|"grapefruit") echo "It's a citrus fruit" ;; *) echo "Unknown fruit: $fruit" ;; esac # ===== SHORT-CIRCUIT CONDITIONALS ===== # Using && (AND) [ -f "/etc/passwd" ] && echo "File exists" # Using || (OR) [ -f "/nonexistent" ] || echo "File does not exist" # Combined [ -f "/etc/passwd" ] && echo "File exists" || echo "File does not exist" # ===== FILE TESTS ===== file="/etc/passwd" dir="/tmp" if [ -e "$file" ]; then echo "Exists"; fi if [ -f "$file" ]; then echo "Regular file"; fi if [ -d "$dir" ]; then echo "Directory"; fi # ===== STRING TESTS ===== str1="hello" str2="" if [ -z "$str2" ]; then echo "String is empty"; fi if [ -n "$str1" ]; then echo "String is not empty"; fi if [ "$str1" = "hello" ]; then echo "Strings equal"; fi # ===== NUMERIC TESTS ===== a=10 b=20 if [ $a -eq 10 ]; then echo "a equals 10"; fi if [ $a -ne $b ]; then echo "a not equal to b"; fi if [ $a -lt $b ]; then echo "a less than b"; fi # ===== COMPOUND CONDITIONS ===== if [[ $a -gt 5 && $b -lt 30 ]]; then echo "Both conditions true (using &&)" fi if [[ $a -gt 20 || $b -lt 30 ]]; then echo "At least one condition true (using ||)" fi # ===== NEGATION ===== if ! [ -f "/nonexistent" ]; then echo "File does not exist (negation)" fi # ===== PRACTICAL EXAMPLES ===== # 1. Check if command exists if command -v python3 &> /dev/null; then echo "Python 3 is installed" else echo "Python 3 is not installed" fi # 2. Check multiple conditions if [ $# -eq 0 ]; then echo "No arguments provided" elif [ $# -eq 1 ]; then echo "One argument: $1" else echo "Multiple arguments" fi # 3. Interactive yes/no prompt read -p "Continue? (y/n): " answer case $answer in [Yy]*) echo "Continuing..." ;; [Nn]*) echo "Exiting..." exit 0 ;; *) echo "Please answer yes or no" ;; esac

🔄 Loops

🎯 Complete Definition

Loops in Bash allow repetitive execution of commands. Bash provides several loop constructs: for loops (iterating over lists), while loops (execute while condition true), until loops (execute until condition true), and select loops (interactive menus).

📋 Loop Types

  • for loop: Iterate over a list of values
  • while loop: Execute while condition is true
  • until loop: Execute until condition becomes true
  • select loop: Create interactive menus
  • break: Exit the loop early
  • continue: Skip to next iteration

🔧 Loop Control

  • break [n]: Exit from loop (n levels)
  • continue [n]: Skip to next iteration (n levels)
  • Loop redirection: Redirect output of entire loop
  • Pipes with loops: Connect loop output to other commands
#!/bin/bash # Loops in Bash # ===== FOR LOOP (TRADITIONAL STYLE) ===== echo "Traditional for loop:" for i in 1 2 3 4 5; do echo "Number: $i" done # ===== FOR LOOP WITH RANGE ===== echo "For loop with range:" for i in {1..10}; do echo -n "$i " done echo "" # Range with step (bash 4+) echo "For loop with step:" for i in {1..10..2}; do echo -n "$i " done echo "" # ===== FOR LOOP WITH C-STYLE SYNTAX ===== echo "C-style for loop:" for ((i=0; i<10; i++)); do echo -n "$i " done echo "" # ===== FOR LOOP OVER ARRAY ===== fruits=("apple" "banana" "orange" "grape" "kiwi") echo "For loop over array:" for fruit in "${fruits[@]}"; do echo "Fruit: $fruit" done # ===== FOR LOOP OVER FILES ===== echo "For loop over files:" for file in /etc/*.conf; do if [ -f "$file" ]; then echo "Config file: $(basename "$file")" fi done | head -5 # ===== WHILE LOOP ===== echo "While loop:" counter=1 while [ $counter -le 5 ]; do echo "Counter: $counter" ((counter++)) done # ===== WHILE LOOP READING FILE ===== echo "While loop reading file:" while IFS= read -r line; do echo "Line: $line" done < /etc/passwd | head -3 # ===== UNTIL LOOP ===== echo "Until loop:" counter=1 until [ $counter -gt 5 ]; do echo "Counter: $counter" ((counter++)) done # ===== SELECT LOOP (MENU) ===== echo "Select loop (choose an option):" options=("Option 1" "Option 2" "Option 3" "Quit") select opt in "${options[@]}"; do case $opt in "Option 1") echo "You chose option 1" ;; "Option 2") echo "You chose option 2" ;; "Option 3") echo "You chose option 3" ;; "Quit") echo "Exiting menu" break ;; *) echo "Invalid option" ;; esac done # ===== NESTED LOOPS ===== echo "Nested loops:" for i in {1..3}; do for j in {1..3}; do echo -n "($i,$j) " done echo "" done # ===== LOOP CONTROL: BREAK ===== echo "Break example:" for i in {1..10}; do if [ $i -eq 5 ]; then echo "Breaking at $i" break fi echo "Number: $i" done # ===== LOOP CONTROL: CONTINUE ===== echo "Continue example:" for i in {1..10}; do if [ $((i % 2)) -eq 0 ]; then continue # Skip even numbers fi echo "Odd number: $i" done # ===== LOOP REDIRECTION ===== echo "Loop output redirection:" for i in {1..5}; do echo "Line $i" done > /tmp/loop_output.txt echo "Output written to /tmp/loop_output.txt" # ===== PRACTICAL EXAMPLES ===== # 1. Find and process files echo "Find and process .sh files:" for script in *.sh; do if [ -f "$script" ] && [ -x "$script" ]; then echo "Executable script: $script" fi done | head -5 # 2. Retry loop with timeout max_attempts=5 attempt=1 while [ $attempt -le $max_attempts ]; do echo "Attempt $attempt of $max_attempts" # Simulate success on attempt 3 if [ $attempt -eq 3 ]; then echo "Success on attempt $attempt" break fi ((attempt++)) sleep 0.5 done # 3. Progress bar example echo -n "Progress: " for i in {1..20}; do echo -n "▓" sleep 0.05 done echo " Done!"

⚙️ Functions

🎯 Complete Definition

Functions in Bash are reusable blocks of code that can be called multiple times. They help organize scripts, reduce code duplication, and improve maintainability. Functions can accept arguments, return values, and have local variables.

📋 Function Components

  • Function name: Identifier for the function
  • Function body: Commands to execute
  • Arguments: Accessible as $1, $2, ... $n
  • Return value: Return status (0-255) or output
  • Local variables: Variables scoped to function

🔧 Function Features

  • Declaration: function name { ... } or name() { ... }
  • Argument handling: $@, $*, $#, shift
  • Return status: return command (0=success, non-zero=failure)
  • Output return: echo/printf to capture output
  • Local variables: local keyword
  • Variable scope: Global by default, local for function
#!/bin/bash # Functions in Bash # ===== BASIC FUNCTION DECLARATION ===== # Method 1: Using function keyword function greet { echo "Hello, World!" } # Method 2: Using parentheses (more common) say_hello() { echo "Hello from say_hello!" } # Call functions greet say_hello # ===== FUNCTION WITH ARGUMENTS ===== greet_person() { local name="$1" echo "Hello, $name!" } greet_person "Alice" greet_person "Bob" # ===== FUNCTION WITH MULTIPLE ARGUMENTS ===== add_numbers() { local num1=$1 local num2=$2 local sum=$((num1 + num2)) echo "Sum of $num1 and $num2 is: $sum" } add_numbers 10 20 # ===== FUNCTION WITH RETURN STATUS ===== is_even() { local num=$1 if [ $((num % 2)) -eq 0 ]; then return 0 # Success (true) else return 1 # Failure (false) fi } is_even 4 && echo "4 is even" || echo "4 is odd" is_even 5 && echo "5 is even" || echo "5 is odd" # ===== FUNCTION RETURNING VALUE VIA ECHO ===== get_greeting() { local name=$1 echo "Hello, $name! Welcome to Bash." } greeting=$(get_greeting "Alice") echo "$greeting" # ===== FUNCTION WITH DEFAULT ARGUMENTS ===== power() { local base=${1:-2} local exponent=${2:-2} echo $((base ** exponent)) } echo "2^2 = $(power)" echo "3^2 = $(power 3)" echo "4^3 = $(power 4 3)" # ===== FUNCTION WITH LOCAL VARIABLES ===== calculate() { local a=$1 local b=$2 local result=$((a * b + 10)) echo "Result: $result" } calculate 5 3 # ===== FUNCTION USING ALL ARGUMENTS ===== print_all() { echo "Number of arguments: $#" echo "All arguments:" for arg in "$@"; do echo " - $arg" done } print_all apple banana orange grape # ===== FUNCTION WITH SHIFT ===== process_args() { while [ $# -gt 0 ]; do echo "Processing: $1" shift done } process_args first second third fourth # ===== RECURSIVE FUNCTION ===== factorial() { local n=$1 if [ $n -le 1 ]; then echo 1 else local prev=$(factorial $((n - 1))) echo $((n * prev)) fi } echo "Factorial of 5: $(factorial 5)" # ===== FUNCTION LIBRARY EXAMPLE ===== # Math functions math_add() { echo $(( $1 + $2 )); } math_sub() { echo $(( $1 - $2 )); } math_mul() { echo $(( $1 * $2 )); } math_div() { echo $(( $1 / $2 )); } # String functions str_length() { echo ${#1}; } str_upper() { echo "${1^^}"; } str_lower() { echo "${1,,}"; } # Use library functions echo "5 + 3 = $(math_add 5 3)" echo "Length of 'hello': $(str_length "hello")" echo "Uppercase: $(str_upper "hello world")" # ===== PRACTICAL EXAMPLES ===== # 1. Logging function log() { local level=$1 shift local message="$*" local timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] [$level] $message" } log "INFO" "Script started" log "ERROR" "Something went wrong" # 2. Configuration file parser parse_config() { local config_file=$1 while IFS='=' read -r key value; do if [[ ! $key =~ ^[[:space:]]*# && -n $key ]]; then key=$(echo $key | xargs) value=$(echo $value | xargs) printf -v "$key" "%s" "$value" fi done < "$config_file" } # Create test config cat > /tmp/test.conf <

📂 I/O & Redirection

🎯 Complete Definition

Input/Output redirection in Bash controls where command input comes from and where output goes. Every command has three standard streams: stdin (0), stdout (1), and stderr (2). Redirection allows connecting commands, files, and devices.

📋 Standard Streams

  • stdin (0): Standard input (keyboard by default)
  • stdout (1): Standard output (terminal by default)
  • stderr (2): Standard error (terminal by default)

🔧 Redirection Operators

  • > - Redirect stdout to file (overwrite)
  • >> - Redirect stdout to file (append)
  • < - Use file as stdin
  • 2> - Redirect stderr to file
  • 2>> - Append stderr to file
  • &> - Redirect both stdout and stderr (overwrite)
  • &>> - Append both stdout and stderr
  • | - Pipe: connect stdout of one command to stdin of another
  • tee - Split output: write to file and stdout
  • Here documents (<<) - Multi-line input
  • Here strings (<<<) - Single-line input
#!/bin/bash # I/O Redirection in Bash # ===== OUTPUT REDIRECTION (stdout) ===== # Overwrite file echo "This goes to file" > /tmp/output.txt cat /tmp/output.txt # Append to file echo "This also goes to file" >> /tmp/output.txt cat /tmp/output.txt # ===== ERROR REDIRECTION (stderr) ===== # Redirect errors to file ls /nonexistent 2> /tmp/error.txt cat /tmp/error.txt # ===== REDIRECT BOTH stdout AND stderr ===== # Method 1: &> (bash-specific) ls /tmp /nonexistent &> /tmp/both.txt cat /tmp/both.txt # Method 2: > file 2>&1 (POSIX-compatible) ls /tmp /nonexistent > /tmp/both2.txt 2>&1 cat /tmp/both2.txt # ===== DISCARD OUTPUT ===== # Discard stdout ls /tmp > /dev/null # Discard stderr ls /nonexistent 2> /dev/null # Discard both ls /tmp /nonexistent &> /dev/null # ===== PIPES ===== # Connect commands echo "hello world" | wc -w # Multiple pipes cat /etc/passwd | cut -d: -f1 | sort | uniq | head -5 # ===== TEE COMMAND ===== # Write to file and stdout simultaneously echo "Important data" | tee /tmp/tee_output.txt cat /tmp/tee_output.txt # Append with tee -a echo "More data" | tee -a /tmp/tee_output.txt # ===== HERE DOCUMENTS ===== # Multi-line input cat < /tmp/here_doc.txt This is line 1 This is line 2 This is line 3 EOF cat /tmp/here_doc.txt # Here document with variable expansion name="Alice" cat < /tmp/loop_output.txt # Redirect loop input while read line; do echo "Read: $line" done < /etc/passwd | head -3 # ===== PRACTICAL EXAMPLES ===== # 1. Logging script output { echo "Script started at $(date)" echo "User: $USER" ls -la echo "Script ended at $(date)" } > /tmp/script_log.txt # 2. Error logging with timestamp { echo "[$(date)] Starting operation" ls /nonexistent 2>&1 echo "[$(date)] Operation completed" } >> /tmp/operation.log 2>&1 # 3. Progress with tee for i in {1..5}; do echo "Processing item $i" sleep 0.1 done | tee /tmp/progress.txt

🔍 Regular Expressions

🎯 Complete Definition

Regular expressions (regex) in Bash are patterns used for matching text. They're used with commands like grep, sed, awk, and in [[ =~ ]] conditional expressions. Bash supports both basic and extended regular expressions.

📋 Regex Types

  • Basic Regular Expressions (BRE): Default in grep, sed
  • Extended Regular Expressions (ERE): grep -E, egrep, sed -E, awk

🔧 Regex Metacharacters

  • . - Any single character
  • * - Zero or more of previous character
  • + - One or more of previous (ERE)
  • ? - Zero or one of previous (ERE)
  • ^ - Start of line/string
  • $ - End of line/string
  • [abc] - Character class (a, b, or c)
  • [^abc] - Negated character class
  • [a-z] - Range
  • {n} - Exactly n times
  • {n,} - n or more times
  • {n,m} - Between n and m times
  • | - Alternation (OR)
  • () - Grouping
  • \ - Escape special character
#!/bin/bash # Regular Expressions in Bash # ===== GREP WITH REGEX ===== echo "=== GREP Examples ===" # Basic regex echo "hello world" | grep "hello" echo "hello world" | grep "^hello" # Starts with hello echo "hello world" | grep "world$" # Ends with world # Character classes echo "cat" | grep "[a-z]at" # Matches cat, bat, rat, etc. echo "123" | grep -E "[0-9]+" # One or more digits # Extended regex with grep -E echo "color colour" | grep -E "colou?r" # Matches both color and colour # ===== SED WITH REGEX ===== echo "=== SED Examples ===" # Substitution echo "Hello World" | sed 's/World/Bash/' # Global substitution echo "one two three two" | sed 's/two/2/g' # Using regex in sed echo "abc123def456" | sed 's/[0-9]\+/NUM/g' # Remove HTML tags echo "

Hello

" | sed 's/<[^>]*>//g' # ===== AWK WITH REGEX ===== echo "=== AWK Examples ===" # Pattern matching echo "apple 10" | awk '/apple/ {print}' # Field matching echo "apple:10:red" | awk -F: '$1 ~ /apple/ {print $2}' # ===== BASH [[ =~ ]] REGEX ===== echo "=== Bash [[ =~ ]] Examples ===" # Test if string matches pattern email="user@example.com" if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then echo "Valid email: $email" else echo "Invalid email" fi # Capture groups phone="123-456-7890" if [[ $phone =~ ^([0-9]{3})-([0-9]{3})-([0-9]{4})$ ]]; then echo "Area code: ${BASH_REMATCH[1]}" echo "Exchange: ${BASH_REMATCH[2]}" echo "Number: ${BASH_REMATCH[3]}" fi # ===== COMMON PATTERNS ===== echo "=== Common Patterns ===" # Email validation email_pattern='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' test_emails=( "user@example.com" "first.last@domain.co.uk" "invalid@email" ) for email in "${test_emails[@]}"; do if [[ $email =~ $email_pattern ]]; then echo "✓ $email" else echo "✗ $email" fi done # URL validation url_pattern='^(https?|ftp)://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(/[^[:space:]]*)?$' test_urls=( "https://example.com" "http://sub.domain.co.uk/page" "ftp://ftp.example.com/file.txt" "invalid-url" ) for url in "${test_urls[@]}"; do if [[ $url =~ $url_pattern ]]; then echo "✓ $url" else echo "✗ $url" fi done # IP address validation ip_pattern='^([0-9]{1,3}\.){3}[0-9]{1,3}$' test_ips=( "192.168.1.1" "10.0.0.255" "256.1.2.3" ) for ip in "${test_ips[@]}"; do if [[ $ip =~ $ip_pattern ]]; then # Additional check for valid range valid=true IFS='.' read -ra octets <<< "$ip" for octet in "${octets[@]}"; do if [ $octet -gt 255 ]; then valid=false break fi done if $valid; then echo "✓ $ip (valid)" else echo "✗ $ip (invalid range)" fi else echo "✗ $ip (invalid format)" fi done # ===== PRACTICAL EXAMPLES ===== # 1. Extract email from text text="Contact us at support@example.com or sales@example.com" emails=$(echo "$text" | grep -o -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}') echo "Found emails: $emails" # 2. Validate and format phone numbers format_phone() { local phone=$1 if [[ $phone =~ ^([0-9]{3})[-.]?([0-9]{3})[-.]?([0-9]{4})$ ]]; then echo "(${BASH_REMATCH[1]}) ${BASH_REMATCH[2]}-${BASH_REMATCH[3]}" else echo "Invalid phone: $phone" fi } format_phone "123-456-7890" format_phone "123.456.7890" format_phone "1234567890" format_phone "12345" # 3. Extract all links from HTML (simple version) html='Example Page' links=$(echo "$html" | grep -o -E 'href="([^"]+)"' | sed 's/href="//;s/"//') echo "Links found:" echo "$links"

⚡ Process Management

🎯 Complete Definition

Process management in Bash involves controlling and monitoring running programs. Bash provides facilities for running processes in the background, foreground, suspending them, and managing job control. Understanding process management is essential for system administration and scripting.

📋 Process Concepts

  • Process ID (PID): Unique identifier for each process
  • Parent Process ID (PPID): ID of the parent process
  • Job: A process or group of processes running from the shell
  • Foreground: Process that has control of the terminal
  • Background: Process running without terminal control
  • Daemon: Background process not attached to a terminal

🔧 Process Commands

  • ps: Display process status
  • top/htop: Interactive process viewer
  • kill: Send signals to processes
  • jobs: List background jobs
  • bg: Resume job in background
  • fg: Resume job in foreground
  • &: Run command in background
  • Ctrl+Z: Suspend foreground process
  • Ctrl+C: Terminate foreground process
  • nohup: Run immune to hangups
  • disown: Remove job from job table
  • wait: Wait for background processes
#!/bin/bash # Process Management in Bash # ===== BACKGROUND PROCESSES ===== echo "Starting background process" sleep 30 & echo "Background process started with PID: $!" # ===== JOB CONTROL ===== echo "=== Job Control ===" # Start a long-running process sleep 60 & sleep 60 & # List jobs echo "Current jobs:" jobs # Bring job to foreground (uncomment to use) # fg %1 # Send job to background # bg %1 # ===== PROCESS INFORMATION ===== echo "=== Process Information ===" # List processes echo "Current shell processes:" ps -f # List all processes echo "All processes (first 5 lines):" ps -ef | head -5 # Process tree echo "Process tree:" pstree -h | head -5 # ===== PROCESS IDS ===== echo "=== Process IDs ===" echo "Current shell PID: $$" echo "Parent shell PID: $PPID" echo "Last background PID: $!" # ===== SIGNALS ===== echo "=== Signals ===" # Function to handle signals handle_signal() { echo "Received signal: $1" } # Set up signal handlers trap 'handle_signal SIGINT' INT trap 'handle_signal SIGTERM' TERM trap 'handle_signal SIGUSR1' USR1 # Send signals to self echo "Sending SIGUSR1 to self" kill -USR1 $$ # ===== WAITING FOR PROCESSES ===== echo "=== Waiting for Processes ===" # Start multiple background processes sleep 2 & pid1=$! sleep 3 & pid2=$! sleep 1 & pid3=$! echo "Waiting for processes to complete..." wait $pid1 $pid2 $pid3 echo "All processes completed" # ===== PROCESS SUBSTITUTION ===== echo "=== Process Substitution ===" # Compare outputs without temporary files diff <(ls /tmp) <(ls /var/tmp) 2>/dev/null || echo "Directories differ" # ===== PIPES AND PROCESSES ===== echo "=== Pipes and Processes ===" # Pipeline creates subshells echo "Pipeline processes:" ps -f | head -3 # ===== PROCESS MONITORING ===== echo "=== Process Monitoring ===" # Check if process is running check_process() { local pid=$1 if kill -0 $pid 2>/dev/null; then echo "Process $pid is running" return 0 else echo "Process $pid is not running" return 1 fi } # Start a process and check it sleep 5 & pid=$! check_process $pid sleep 6 check_process $pid # ===== PROCESS PRIORITY ===== echo "=== Process Priority ===" # Start process with lower priority (nice) nice -n 19 sleep 10 & echo "Started low priority process with PID: $!" # Change priority (renice) - requires root # renice +5 $pid # ===== PROCESS LIMITS ===== echo "=== Process Limits ===" echo "Max user processes: $(ulimit -u)" echo "Open file limit: $(ulimit -n)" # ===== DAEMON PROCESS ===== echo "=== Daemon Process Example ===" # Simple daemon function run_daemon() { while true; do echo "Daemon running at $(date)" >> /tmp/daemon.log sleep 5 done } # Start daemon (uncomment to run) # run_daemon & # echo "Daemon started with PID: $!" # ===== PRACTICAL EXAMPLES ===== # 1. Process monitoring script monitor_process() { local process_name=$1 local pid=$(pgrep -f "$process_name" | head -1) if [ -n "$pid" ]; then echo "Process $process_name (PID: $pid) is running" echo "CPU usage: $(ps -p $pid -o %cpu | tail -1)%" echo "Memory usage: $(ps -p $pid -o %mem | tail -1)%" echo "Runtime: $(ps -p $pid -o etime | tail -1)" else echo "Process $process_name not found" fi } # Monitor a process monitor_process "bash" # 2. Timeout command timeout_command() { local timeout=$1 shift local cmd=("$@") "${cmd[@]}" & local pid=$! sleep $timeout if kill -0 $pid 2>/dev/null; then kill $pid echo "Command timed out after $timeout seconds" return 1 fi wait $pid return $? } # Test timeout timeout_command 2 sleep 5 || echo "Command failed" # 3. Parallel process limit run_parallel() { local max_procs=$1 shift local commands=("$@") local running=0 local pids=() for cmd in "${commands[@]}"; do # Wait if we've reached max processes while [ ${#pids[@]} -ge $max_procs ]; do for i in "${!pids[@]}"; do if ! kill -0 ${pids[$i]} 2>/dev/null; then unset pids[$i] fi done pids=("${pids[@]}") sleep 0.1 done # Run command eval "$cmd" & pids+=($!) echo "Started: $cmd (PID: $!)" done # Wait for remaining processes wait } # Test parallel execution run_parallel 3 \ "sleep 2" \ "sleep 3" \ "sleep 1" \ "sleep 4" \ "sleep 2" # 4. Process tree killer kill_tree() { local parent_pid=$1 local signal=${2:-TERM} # Get child PIDs local children=$(pgrep -P $parent_pid) # Kill children first for child in $children; do kill_tree $child $signal done # Kill parent kill -$signal $parent_pid 2>/dev/null echo "Killed process $parent_pid" } # Example: kill_tree 1234 # 5. Process resource monitor resource_monitor() { local pid=$1 local interval=${2:-1} echo "Monitoring PID $pid every $interval second(s)" echo "Time CPU% MEM% VSZ RSS" while kill -0 $pid 2>/dev/null; do ps -p $pid -o pcpu=,pmem=,vsz=,rss= | while read cpu mem vsz rss; do printf "%(%H:%M:%S)T %5.1f %5.1f %7d %6d\n" -1 $cpu $mem $vsz $rss done sleep $interval done } # Start a process and monitor it sleep 30 & monitor_pid=$! echo "Monitoring process $monitor_pid for 5 seconds..." resource_monitor $monitor_pid 1 & sleep 5 kill $monitor_pid

📜 Scripting

🎯 Complete Definition

Bash scripting involves writing sequences of commands in a file to automate tasks, create tools, and build complex workflows. Scripts combine all Bash features into reusable programs that can handle command-line arguments, interact with users, and perform system administration.

📋 Script Components

  • Shebang: #!/bin/bash - Specifies interpreter
  • Comments: # for documentation
  • Variables: Store and manipulate data
  • Functions: Reusable code blocks
  • Control structures: Conditionals and loops
  • Input/Output: Reading input, printing output
  • Error handling: Exit codes, error messages

🔧 Script Features

  • Command-line arguments: $1, $2, ..., $@, $*
  • Options parsing: getopts for handling flags
  • Exit codes: 0 for success, non-zero for errors
  • Debugging: set -x, set -e, bash -x script.sh
  • Strict mode: set -euo pipefail
  • User input: read command
  • Temporary files: mktemp
#!/bin/bash # Bash Scripting - Complete Examples # ===== STRICT MODE ===== # Exit on error, undefined variable, and pipe failure set -euo pipefail IFS=$'\n\t' # ===== SCRIPT INFORMATION ===== echo "=== Script Information ===" echo "Script name: $0" echo "Script directory: $(dirname "$0")" echo "Script PID: $$" # ===== COMMAND LINE ARGUMENTS ===== echo "=== Command Line Arguments ===" echo "Number of arguments: $#" echo "All arguments: $@" # ===== OPTIONS PARSING WITH GETOPTS ===== echo "=== Options Parsing ===" usage() { echo "Usage: $0 [-h] [-v] [-f file] [-n count]" echo " -h Show this help" echo " -v Verbose mode" echo " -f Input file" echo " -n Number (default: 10)" exit 1 } verbose=0 file="" count=10 while getopts "hvf:n:" opt; do case $opt in h) usage ;; v) verbose=1 ;; f) file="$OPTARG" ;; n) count="$OPTARG" ;; \?) echo "Invalid option: -$OPTARG" >&2 usage ;; esac done echo "Verbose: $verbose" echo "File: $file" echo "Count: $count" # ===== USER INPUT ===== echo "=== User Input ===" # Simple prompt read -p "Enter your name: " name echo "Hello, $name!" # Password input read -s -p "Enter password: " password echo echo "Password length: ${#password}" # Multiple values read -p "Enter three numbers: " num1 num2 num3 echo "Numbers: $num1, $num2, $num3" # ===== ERROR HANDLING ===== echo "=== Error Handling ===" # Function with error checking safe_divide() { local dividend=$1 local divisor=$2 if [ $divisor -eq 0 ]; then echo "Error: Division by zero" >&2 return 1 fi echo $((dividend / divisor)) return 0 } # Call with error checking if result=$(safe_divide 10 2); then echo "Result: $result" else echo "Division failed" fi # ===== TEMPORARY FILES ===== echo "=== Temporary Files ===" # Create temp file temp_file=$(mktemp) echo "Temporary file: $temp_file" # Write to temp file cat > "$temp_file" < "$config_file" < /tmp/backup.sh <<'EOF' #!/bin/bash set -euo pipefail # Backup script backup_dir="${HOME}/backups" source_dir="${1:-.}" max_backups=${2:-5} # Create backup directory if needed mkdir -p "$backup_dir" # Create backup name timestamp=$(date '+%Y%m%d_%H%M%S') backup_name="backup_${timestamp}.tar.gz" backup_path="${backup_dir}/${backup_name}" echo "Creating backup of $source_dir -> $backup_path" tar -czf "$backup_path" "$source_dir" # Rotate old backups cd "$backup_dir" ls -t backup_*.tar.gz | tail -n +$((max_backups + 1)) | xargs -r rm echo "Backup completed. $(ls -1 backup_*.tar.gz 2>/dev/null | wc -l) backups kept." EOF chmod +x /tmp/backup.sh echo "Created /tmp/backup.sh" } create_backup_script # ===== SELF-CONTAINED SCRIPT TEMPLATE ===== echo "=== Script Template ===" cat <<'EOF' > /tmp/template.sh #!/bin/bash set -euo pipefail IFS=$'\n\t' # Script: template.sh # Description: Template for bash scripts # Author: CodeOrbitPro # Version: 1.0 # Configuration readonly SCRIPT_NAME=$(basename "$0") readonly SCRIPT_DIR=$(dirname "$0") readonly VERSION="1.0" # Default values verbose=0 config_file="" # Functions usage() { cat <&2 fi } # Parse arguments while [ $# -gt 0 ]; do case $1 in -h|--help) usage ;; --version) version ;; -v|--verbose) verbose=1 shift ;; -c|--config) config_file="$2" shift 2 ;; --) shift break ;; -*) echo "Unknown option: $1" >&2 usage ;; *) break ;; esac done # Main script log "INFO" "Script started" log "INFO" "Verbose mode: $verbose" log "INFO" "Config file: $config_file" log "INFO" "Remaining arguments: $*" # Your script logic here for arg in "$@"; do log "INFO" "Processing argument: $arg" done log "INFO" "Script completed successfully" EOF chmod +x /tmp/template.sh echo "Created /tmp/template.sh" # ===== SCRIPT WRAPPER ===== echo "=== Script Wrapper ===" # Wrapper that runs script with timeout and logging run_with_wrapper() { local script=$1 shift local log_file="/tmp/wrapper_$$.log" { echo "=== Wrapper started at $(date) ===" echo "Script: $script" echo "Arguments: $*" echo "=== Script output ===" # Run with timeout timeout 30 "$script" "$@" 2>&1 local exit_code=$? echo "=== Script completed with exit code: $exit_code ===" echo "=== Wrapper finished at $(date) ===" } | tee "$log_file" return $exit_code } # Test wrapper echo "echo 'Hello from script'" > /tmp/test.sh chmod +x /tmp/test.sh run_with_wrapper /tmp/test.sh rm /tmp/test.sh # Cleanup rm -f /tmp/backup.sh /tmp/template.sh

🔬 Advanced Bash

🎯 Complete Definition

Advanced Bash covers sophisticated techniques for writing robust, efficient, and maintainable shell scripts. This includes advanced expansions, coprocesses, named pipes, process substitution, and integration with other tools.

🔬 Advanced Features

  • Brace Expansion: {1..10}, {a..z}, {file1,file2}.txt
  • Process Substitution: <(command), >(command)
  • Coprocesses: Two-way communication with processes
  • Named Pipes (FIFOs): Inter-process communication
  • Extended Globbing: Pattern matching extensions
  • Indirect Expansion: ${!var}
  • Parameter Transformation: ${var@Q}, ${var@E}, ${var@P}
  • Associative Arrays: declare -A
  • Loadable Builtins: Extending bash with C modules

⚡ Performance Optimization

  • Builtins vs External: Use builtins when possible
  • Minimize subshells: Avoid unnecessary pipes
  • Use printf instead of echo: More portable and efficient
  • Bash vs external tools: Know when to use awk/sed
  • Parallel execution: Background jobs, xargs -P
#!/bin/bash # Advanced Bash Programming # ===== BRACE EXPANSION ===== echo "=== Brace Expansion ===" # Number ranges echo {1..10} echo {01..10} echo {1..10..2} # Letter ranges echo {a..z} echo {A..Z} echo {a..z..2} # Combinations echo {file1,file2,file3}.txt echo {user1,user2}@{host1,host2}.com # Nested brace expansion echo {a,b{1,2,3},c} # ===== PROCESS SUBSTITUTION ===== echo "=== Process Substitution ===" # Compare command outputs diff <(ls /tmp) <(ls /var/tmp) 2>/dev/null || echo "Directories differ" # Feed multiple process outputs paste <(seq 1 5) <(seq 10 15) <(seq 20 25) # Process substitution for input while read line; do echo "Read: $line" done < <(ls -la) # Process substitution for output exec > >(tee /tmp/output.log) echo "This goes to both stdout and log file" exec > /dev/tty # ===== COPROCESSES ===== echo "=== Coprocesses ===" # Create a coprocess coproc bc { bc -l } # Send input to coprocess echo "scale=10; 4*a(1)" >&${COPROC[1]} # Read output read -u ${COPROC[0]} result echo "Pi from bc: $result" # Close coprocess exec {COPROC[1]}>&- exec {COPROC[0]}<&- # ===== NAMED PIPES (FIFOs) ===== echo "=== Named Pipes ===" # Create a named pipe fifo="/tmp/myfifo.$$" mkfifo "$fifo" # Write to pipe in background echo "Hello through pipe" > "$fifo" & # Read from pipe read line < "$fifo" echo "Received: $line" # Clean up rm "$fifo" # ===== EXTENDED GLOBBING ===== echo "=== Extended Globbing ===" # Enable extended globbing shopt -s extglob # Pattern examples echo "Extended globbing patterns:" cd /tmp # ?(pattern) - zero or one occurrence echo "?(file).txt matches file.txt or .txt" # *(pattern) - zero or more occurrences echo "*(file).txt matches .txt, file.txt, filefile.txt" # +(pattern) - one or more occurrences echo "+(file).txt matches file.txt, filefile.txt" # @(pattern1|pattern2) - exactly one of the patterns echo "@(file|doc).txt matches file.txt or doc.txt" # !(pattern) - anything but the pattern echo "!(file).txt matches anything not file.txt" # Examples touch file.txt doc.txt data.txt ls *.txt ls @(file|doc).txt ls !(file).txt # Clean up rm -f file.txt doc.txt data.txt # Disable extended globbing shopt -u extglob # ===== INDIRECT EXPANSION ===== echo "=== Indirect Expansion ===" var1="Hello" var2="World" ref="var1" echo "Indirect expansion: ${!ref}" # Dynamic variable names for i in {1..5}; do declare var$i="Value $i" done for i in {1..5}; do ref="var$i" echo "var$i = ${!ref}" done # ===== PARAMETER TRANSFORMATION ===== echo "=== Parameter Transformation ===" text=$'Hello\nWorld\t!' # Quote transformation echo "@Q: ${text@Q}" # Escape transformation echo "@E: ${text@E}" # Prompt transformation PS1='\u@\h' echo "@P: ${PS1@P}" # ===== LOADABLE BUILTINS ===== echo "=== Loadable Builtins ===" # Enable loadable builtins (if available) # enable -f /path/to/builtin.so builtin_name # Example: using 'cut' as builtin (not standard) if enable -f /usr/lib/bash/cut cut 2>/dev/null; then echo "cut builtin loaded" cut -d: -f1 <<< "a:b:c" else echo "cut builtin not available" fi # ===== ASSOCIATIVE ARRAYS ADVANCED ===== echo "=== Advanced Associative Arrays ===" declare -A data # Store complex data data["user1,name"]="John Doe" data["user1,age"]=30 data["user1,city"]="New York" data["user2,name"]="Jane Smith" data["user2,age"]=25 data["user2,city"]="Los Angeles" # Iterate by key pattern for key in "${!data[@]}"; do if [[ $key == user1,* ]]; then echo "User1 $key = ${data[$key]}" fi done # Nested data structure declare -A users users[1]="John:30:NYC" users[2]="Jane:25:LA" for id in "${!users[@]}"; do IFS=':' read -r name age city <<< "${users[$id]}" echo "User $id: $name, $age, $city" done # ===== ADVANCED REDIRECTION ===== echo "=== Advanced Redirection ===" # Redirect multiple file descriptors exec 3> /tmp/file3.txt exec 4> /tmp/file4.txt exec 5<&0 # Save stdin echo "To file 3" >&3 echo "To file 4" >&4 # Restore and close exec 3>&- exec 4>&- exec 0<&5 5<&- # ===== NETWORK PROGRAMMING ===== echo "=== Network Programming ===" # TCP/UDP redirection (bash 4+) if [ -e /dev/tcp ]; then # Simple HTTP request exec 3<>/dev/tcp/example.com/80 echo -e "GET / HTTP/1.0\nHost: example.com\n\n" >&3 cat <&3 | head -5 exec 3>&- fi # ===== DEBUGGING TECHNIQUES ===== echo "=== Debugging Techniques ===" # Trace execution set -x echo "This is traced" x=5 y=10 echo "x + y = $((x + y))" set +x # Verbose mode set -v echo "This is verbose" set +v # Error checking set -e # Exit on error set -u # Exit on undefined variable # Custom debug function debug() { if [ "${DEBUG:-0}" -eq 1 ]; then echo "DEBUG: $*" >&2 fi } DEBUG=1 debug "This is a debug message" # ===== PERFORMANCE OPTIMIZATION ===== echo "=== Performance Optimization ===" # Time commands time for i in {1..1000}; do : # Null command done # Use builtins instead of externals # Slow: $(cat file) # Fast: $(> "$0" echo "Script modified itself" } # 5. State machine example declare -A state state["current"]="START" transition() { local event=$1 case ${state["current"]} in START) if [ "$event" = "begin" ]; then state["current"]="RUNNING" echo "Started" fi ;; RUNNING) if [ "$event" = "pause" ]; then state["current"]="PAUSED" elif [ "$event" = "end" ]; then state["current"]="END" echo "Finished" fi ;; PAUSED) if [ "$event" = "resume" ]; then state["current"]="RUNNING" elif [ "$event" = "end" ]; then state["current"]="END" fi ;; esac } transition "begin" transition "pause" transition "resume" transition "end" # 6. Meta-programming: create getters/setters make_property() { local var=$1 eval " get_$var() { echo \$$var } set_$var() { $var=\$1 } " } name="" make_property name set_name "John Doe" echo "Name: $(get_name)" # Cleanup rm -f /tmp/file3.txt /tmp/file4.txt /tmp/temp_$$