Skip to main content

Command Palette

Search for a command to run...

Day 9: Linux - Comprehensive Shell Scripting

Updated
14 min readView as Markdown
Day 9: Linux - Comprehensive Shell Scripting
A

Experienced Senior DevOps Engineer with a passion for optimizing software development and delivery processes. Excels in designing and implementing CI/CD pipelines, automating infrastructure, and optimizing cloud architectures. Proficient in a wide range of DevOps tools such as Docker, Kubernetes, Jenkins, Ansible, Git, and AWS services. Strong collaborator, adept at fostering cross-functional teamwork and continuous improvement. Thrives in dynamic environments, utilizing problem-solving skills to overcome complex challenges. Dedicated to delivering high-quality software products on time and within budget.

Overview:

Welcome to the Comprehensive Shell Scripting! In this blog, you will learn the fundamentals of shell scripting, a powerful skill for automating tasks and managing systems efficiently in Unix-based environments. Whether you are a system administrator, developer, or IT professional, this blog will equip you with the knowledge and proper understanding needed to become proficient in shell scripting.

I: Introduction to Shell Scripting

  1. What is Shell Scripting?
    Shell scripting is a way to write scripts that automate tasks by running shell commands in a sequence. It allows users to interact with the operating system through the command-line interface, making it a powerful tool for automating repetitive tasks and managing system configurations.

  2. Advantages of Shell Scripting

    • Automation: Shell scripts automate complex and repetitive tasks, reducing manual intervention.

    • Rapid Prototyping: It enables quick testing and implementation of ideas.

    • System Management: Shell scripts facilitate system administration tasks, such as backups and updates.

  3. Getting Started with the Shell (bash)
    To begin with, the bash shell, open a terminal and type bash to enter the interactive mode. You can execute shell commands and see their output in real time.

  4. Basic Shell Commands and Syntax

    Shell commands are executed in the terminal.
    For example:

     ls                 # List files in the current directory
     mkdir AnkushDevOps # Create a new directory called "DevOps"
     cd AnkushDevOps    # Change directory to "AnkushDevOps"
    
  5. Writing and Executing Your First Shell Script
    Create a file named hello.sh with the following content:

     #!/bin/bash
     echo "Hello, This is Ankush, writing blog on shell scripting!"
    

    Save the file, and make it executable with chmod +x hello.sh, and run it with ./hello.sh

  6. Understanding Variables and Data Types
    Variables store data in shell scripts. They are not type-bound.
    Example:

     name="Ankush"
     age=28
     echo "My name is $name, and I am $age years old."
    

II: Control Structures and Decision Making

  1. Using Conditional Statements (if, else, elif)
    Conditional statements allow executing of code blocks based on conditions. Example:

     age=25
     if [ $age -ge 18 ]; then
         echo "You are an adult."
     else
         echo "You are a minor."
     fi
    
  2. Performing Logical Operations

    Logical operators (&& for AND, || for OR, ! for NOT) help build complex conditions.

    Example:

     age=25
     if [ $age -ge 18 ] && [ $age -lt 60 ]; then
         echo "You are a working adult."
     fi
    
  3. Working with Comparison Operators
    Comparison operators (-eq, -ne, -lt, -gt, -le, -ge) compare values.
    Example:

     num=10
     if [ $num -eq 10 ]; then
         echo "The number is 10."
     fi
    
  4. Nested Conditionals
    You can use nested if statements for complex conditions.
    Example:

     age=25
     if [ $age -ge 18 ]; then
         if [ $age -lt 60 ]; then
             echo "You are a working adult."
         fi
     fi
    
  5. Case Statements for Multi-choice Decisions
    Case statements provide a multi-choice decision structure.
    Example:

     fruit="apple"
     case $fruit in
         "apple") echo "It's an apple.";;
         "banana") echo "It's a banana.";;
         *) echo "It's something else.";;
     esac
    
  6. Using Test and [[ ]] for Conditional Expressions
    The test command and [[ ]] provide additional conditional expressions. Example:

     num=5
     if [[ $num -eq 5 && ($num -lt 10 || $num -gt 0) ]]; then
         echo "The number is between 0 and 10."
     fi
    

III: Looping Constructs

1. Introduction to Shell Loops (for, while, until)
Shell loops allow you to repeat a block of code multiple times based on a condition. There are three main types of loops in shell scripting:

  • For Loop: The for loop iterates over a list of items (e.g., numbers, strings) and executes a block of code for each item in the list.

  • While Loop: The while loop repeatedly executes a block of code as long as a specified condition is true.

  • Until Loop: The until loop is similar to the while loop but continues until the specified condition becomes true.

Example:

#!/bin/bash

# For loop
for i in 1 2 3 4 5
do
    echo "Iteration $i"
done

# While loop
count=1
while [ $count -le 5 ]
do
    echo "Count: $count"
    ((count++))
done

# Until loop
num=1
until [ $num -gt 5 ]
do
    echo "Number: $num"
    ((num++))
done

2. Iterating Over Lists with the For Loop
The for loop is often used to iterate over a list of items, such as numbers or strings. The loop variable takes each item from the list, and the code block is executed for each item.

Example:

#!/bin/bash

# For loop to iterate over numbers
for num in 1 2 3 4 5
do
    echo "Number: $num"
done

# For loop to iterate over strings
fruits=("apple" "banana" "orange")
for fruit in "${fruits[@]}"
do
    echo "Fruit: $fruit"
done

3. Count-Controlled and Condition-Controlled Loops
In count-controlled loops, the loop executes a fixed number of times based on a specified count. In condition-controlled loops, the loop continues until a certain condition becomes false.

Example - Count-Controlled Loop:

#!/bin/bash

# Count-controlled loop
for ((i=1; i<=5; i++))
do
    echo "Iteration $i"
done

Example - Condition-Controlled Loop:

#!/bin/bash

# Condition-controlled loop
count=1
while [ $count -le 5 ]
do
    echo "Count: $count"
    ((count++))
done

4. Loop Control Statements (break, continue)

Loop control statements provide ways to modify the behaviour of loops. break terminates the loop prematurely, while continue skip the rest of the current iteration and moves to the next one.

Example:

#!/bin/bash

# Using break and continue in a loop
for i in 1 2 3 4 5
do
    if [ $i -eq 3 ]; then
        break  # Terminate the loop when i is 3
    elif [ $i -eq 2 ]; then
        continue  # Skip iteration when i is 2
    fi
    echo "Iteration $i"
done

IV: Arrays and Advanced Variable Techniques

1. Working with Arrays in Shell Scripts

Arrays in shell scripts allow you to store multiple values in a single variable. To declare an array, use array_name=(value1 value2 ...). You can access array elements using ${array_name[index]}.

Example:

#!/bin/bash

# Declaring and accessing array elements
fruits=("apple" "banana" "orange")
echo "First fruit: ${fruits[0]}"

2. Indexing and Accessing Array Elements

Array indices start from 0. You can access individual elements using their index.

Example:

#!/bin/bash

# Indexing and accessing array elements
fruits=("apple" "banana" "orange")
echo "First fruit: ${fruits[0]}"
echo "Second fruit: ${fruits[1]}"

3. Looping Through Arrays

You can use loops to iterate through all elements of an array.

Example:

#!/bin/bash

# Looping through an array
fruits=("apple" "banana" "orange")
for fruit in "${fruits[@]}"
do
    echo "Fruit: $fruit"
done

4. Associative Arrays (bash 4+)

Associative arrays allow you to use strings as indices, providing a more flexible way to access array elements.

Example:

#!/bin/bash

# Associative array
declare -A colors
colors["red"]="#FF0000"
colors["green"]="#00FF00"
colors["blue"]="#0000FF"

# Accessing elements using string indices
echo "Red: ${colors["red"]}"
echo "Green: ${colors["green"]}"
echo "Blue: ${colors["blue"]}"

5. Advanced Variable Manipulation

Shell scripting allows for various variable manipulation techniques, including substring extraction and string length calculation.

Example:

#!/bin/bash

# Advanced variable manipulation
str="Hello, World!"
substring=${str:0:5}  # Extract the first 5 characters
length=${#str}        # Calculate the length of the string

echo "Substring: $substring"
echo "String length: $length"

In this example, substring will contain "Hello," and length will be 13.

V: Command Line Arguments and Input/Output Redirection

1. Accessing Command-Line Arguments

Shell scripts can take input arguments from the command line when they are executed. These arguments can be accessed using special variables: $1, $2, $3, and so on. $0 holds the name of the script itself, and $# stores the total number of arguments.

Example:

#!/bin/bash

# Accessing command-line arguments
echo "Script Name: $0"
echo "First Argument: $1"
echo "Second Argument: $2"
echo "Total Arguments: $#"

If the above script is executed as ./script.sh arg1 arg2, it will output:

Script Name: ./script.sh
First Argument: arg1
Second Argument: arg2
Total Arguments: 2

2. Parsing Options and Flags

In more complex scripts, you may want to provide options or flags to modify the script's behaviour. You can parse these options using conditional statements and the $1, $2, etc., variables.

Example:

#!/bin/bash

# Parsing options and flags
while [[ $# -gt 0 ]]; do
    case $1 in
        -a|--optionA)
            echo "Option A is enabled."
            ;;
        -b|--optionB)
            echo "Option B is enabled."
            ;;
        *)
            echo "Unknown option: $1"
            ;;
    esac
    shift
done

If the above script is executed as ./script.sh -a -b, it will output:

Option A is enabled.
Option B is enabled.

3. Using getopt for More Complex Argument Handling

getopt is a command-line utility that simplifies parsing command-line arguments with more complex options and flags. It allows you to handle short and long options, options with values, and more.

Example:

#!/bin/bash

# Using getopt for complex argument handling
options=$(getopt -o ab:c --long optionA,optionB:,optionC -- "$@")
eval set -- "$options"

while true; do
    case "$1" in
        -a|--optionA)
            echo "Option A is enabled."
            ;;
        -b|--optionB)
            optionBValue="$2"
            echo "Option B is enabled with value: $optionBValue"
            shift
            ;;
        -c|--optionC)
            echo "Option C is enabled."
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "Unknown option: $1"
            ;;
    esac
    shift
done

If the above script is executed as ./script.sh -a -b value -c, it will output:

Option A is enabled.
Option B is enabled with value: value
Option C is enabled.

4. Input/Output Redirection (stdin, stdout, stderr)

In shell scripting, you can redirect input and output streams of commands using special characters. < is used for input redirection (stdin), > for output redirection (stdout), and 2> for error redirection (stderr).

Example:

#!/bin/bash

# Input/Output Redirection
echo "Hello, World!" > output.txt  # Redirect stdout to a file
ls no_directory 2> error.txt      # Redirect stderr to a file
cat < input.txt                   # Redirect stdin from a file

5. Writing to and Reading from Files

You can use file redirection to read data from files or write data to files.

Example - Writing to a File:

#!/bin/bash

# Writing to a file
echo "Line 1" > data.txt
echo "Line 2" >> data.txt  # Append to the file

Example - Reading from a File:

#!/bin/bash

# Reading from a file
while IFS= read -r line
do
    echo "Line: $line"
done < data.txt

VI: String Manipulation and Text Processing

1. Manipulating Strings (Concatenation, Substitution)

Shell scripts provide various ways to manipulate strings, such as concatenation, substitution, and extraction of substrings.

Example:

#!/bin/bash

# Manipulating strings
name="Ankush"
greeting="Hello"
message="$greeting, $name!"
echo $message

# Substring extraction
substring=${message:6}  # Extract "Ankush!"
echo $substring

2. Regular Expressions in Shell Scripting

Regular expressions (regex) allow you to match and manipulate text patterns. They are used in various text-processing tasks.

Example:

#!/bin/bash

# Regular expression matching
string="apple banana orange"
if [[ $string =~ "apple" ]]; then
    echo "Found 'apple'"
fi

3. Using grep, sed, and awk for Text Processing grep, sed, and awk are powerful tools for text processing in shell scripts. grep searches for patterns in text, sed performs text transformations, and awk is a versatile text processing tool.

Example - Using grep:

#!/bin/bash

# Using grep to search for a pattern
file="data.txt"
pattern="apple"
if grep -q "$pattern" "$file"; then
    echo "Found '$pattern' in $file"
fi

Example - Using sed:

#!/bin/bash

# Using sed to replace a word in a file
file="data.txt"
pattern="apple"
replacement="orange"
sed -i "s/$pattern/$replacement/g" "$file"

Example - Using awk:

#!/bin/bash

# Using awk to process data
awk '{ print $1 }' data.txt

In this example, awk prints the first column of data in data.txt.

VII: Functions and Modular Scripting

1. Understanding Shell Functions

Functions in shell scripts are blocks of code that can be defined once and executed multiple times. They provide modularity and help break down complex tasks into smaller, reusable components.

Example:

#!/bin/bash

# Function definition
greet() {
    echo "Hello, Dosto, I am Ankush Yadav!"
}

# Function call
greet

2. Creating and Calling Functions

To create a function, use the syntax function_name() { code_block }. To call a function, simply use its name followed by parentheses.

Example:

#!/bin/bash

# Function definition
welcome() {
    echo "Welcome to the shell scripting course by Ankush!"
}

# Function call
welcome

3. Function Arguments and Return Values

Functions can accept arguments, which can be accessed within the function using positional parameters: $1, $2, etc. Functions can also return values using the return statement.

Example:

#!/bin/bash

# Function with arguments and return value
add() {
    sum=$(( $1 + $2 ))
    return $sum
}

# Function call with arguments
add 5 10
result=$?
echo "Sum: $result"

4. Creating Modular and Reusable Scripts

By using functions, you can create modular and reusable scripts. Functions encapsulate specific tasks, making it easier to manage and maintain the codebase.

Example:

#!/bin/bash

# Function to print a greeting
greet() {
    echo "Hello, $1!"
}

# Function to print a farewell
farewell() {
    echo "Goodbye, $1!"
}

# Main script
name="Ankush"
greet $name
# ... some other code ...
farewell $name

5. Best Practices for Function Design

  • Keep functions short and focused on a single task.

  • Use descriptive function names to indicate their purpose.

  • Avoid global variables within functions to prevent unintended side effects.

  • Provide meaningful comments to explain the function's purpose and usage.

VIII: Process Control and Signals

1. Managing Processes with Shell Scripts can interact with processes by starting, stopping, and managing them.

Example:

#!/bin/bash

# Starting a background process
nohup ./myscript.sh &

2. Process Identification and Control (ps, kill) ps is used to display information about running processes, and kill is used to send signals to processes for termination or other actions.

Example:

#!/bin/bash

# Finding process IDs and killing a process
ps -ef | grep myscript.sh  # Find the process ID of the script
kill PID  # Replace PID with the actual process ID

3. Sending Signals to Processes

Processes can be controlled by sending signals to them. Common signals are SIGTERM (terminate) and SIGKILL (forcefully terminate).

Example:

#!/bin/bash

# Sending signals to a process
kill -SIGTERM PID  # Terminate the process with PID
kill -SIGKILL PID  # Forcefully terminate the process with PID

4. Handling Signals in Scripts

Shell scripts can trap signals to perform specific actions when a signal is received.

Example:

#!/bin/bash

# Trap signals in a script
cleanup() {
    echo "Cleaning up..."
    # Add cleanup logic here
}

trap cleanup SIGINT SIGTERM

while true; do
    # Your script logic here
    sleep 1
done

5. Handling Background Processes and Job Control

Background processes can be started by appending & to a command. Job control allows managing background jobs using bg, fg, and jobs commands.

Example:

#!/bin/bash

# Running a background job
./long_running_task.sh &

# Bringing a background job to the foreground
fg %1

# Listing background jobs
jobs

IX: Advanced Scripting Techniques

1. Using Here Documents and Here Strings

Here documents allow you to embed multiple lines of input directly into a script or command. Here strings are a simplified version used for single-line input.

Example - Here Document:

#!/bin/bash

# Here document
cat << EOF
This is a multi-line
text block using a here document.
EOF

Example - Here String:

#!/bin/bash

# Here string
message=$(cat <<< "Hello, World!")
echo $message

2. Process Substitution for Input/Output Redirection

Process substitution allows you to use the output of a command as a file for input/output redirection.

Example - Input Redirection with Process Substitution:

#!/bin/bash

# Input redirection with process substitution
sort <(cat file1.txt file2.txt)

Example - Output Redirection with Process Substitution:

#!/bin/bash

# Output redirection with process substitution
cat > >(tee output.txt)

3. Generating Random Numbers and Working with Dates

Shell scripting provides methods to generate random numbers and manipulate date/time.

Example - Generating Random Numbers:

#!/bin/bash

# Generating random numbers
random_number=$((RANDOM % 100))
echo "Random number: $random_number"

Example - Working with Dates:

#!/bin/bash

# Working with dates
current_date=$(date +"%Y-%m-%d")
echo "Current date: $current_date"

4. Working with Environment Variables are global variables that store information about the environment in which the shell is running.

Example:

#!/bin/bash

# Working with environment variables
echo "User: $USER"
echo "Home directory: $HOME"
echo "Path: $PATH"

5. Using Traps for Error Handling and Cleanup

Traps allow you to handle signals or errors in scripts and perform cleanup actions before exiting.

Example:

#!/bin/bash

# Using traps for error handling and cleanup
cleanup() {
    echo "Cleaning up..."
    # Add cleanup logic here
}

trap cleanup EXIT

# Your script logic here

X: Scripting Best Practices and Shell Script Security

1. Writing Clean and Maintainable Shell Scripts

  • Use meaningful variable and function names.

  • Add comments to explain complex logic.

  • Indent code properly for readability.

2. Debugging and Troubleshooting Scripts

  • Use set -x to enable debugging mode.

  • Echo intermediate results during script development.

  • Use set +x to disable debugging mode.

3. Shell Script Security Considerations

  • Avoid using eval with untrusted data.

  • Sanitize and validate user input to prevent code injection.

  • Set appropriate permissions for sensitive files and directories.

4. Safe Handling of User Input and Command Execution

  • Use read to prompt and read user input safely.

  • Avoid direct command execution with user input; prefer using variables.

5. Resources for Further Learning and Practice

  • Online tutorials and documentation (e.g., Bash manual).

  • Shell scripting books and courses.

  • Community forums and discussion groups for sharing knowledge.

🙏 Special thanks to all readers who took the time to go through this comprehensive guide. Happy scripting, and stay tuned for more exciting content! 🚀🐚

More from this blog

Untitled Publication

68 posts