Mastering the Shell: Unleashing the Power of Bash Scripting

Shell scripting is a powerful tool for automating tasks, managing systems, and enhancing your productivity within a Linux or Unix-like environment. Bash, the Bourne Again Shell, is the most common shell and provides a robust scripting language. This chapter will introduce you to the fundamentals of Bash scripting and demonstrate its capabilities through practical examples.

1. Introduction to Bash Scripting

A shell script is a plain text file containing a series of commands that the shell executes sequentially. These commands can include system utilities, shell built-ins, and even other scripts.

1.1. Creating and Executing Scripts

  1. Create a script: Open a text editor and write your commands.
  2. Save the script: Save the file with a .sh extension (e.g., my_script.sh).
  3. Make it executable: Use chmod +x my_script.sh.
  4. Run the script: Execute it from the terminal using ./my_script.sh.

1.2. The Shebang (#!)

The first line of a script, the shebang, specifies the interpreter to use. For Bash scripts, it’s #!/bin/bash or #!/bin/sh (for more basic shell compatibility).

2. Basic Scripting Concepts

2.1. Variables

Variables store data. Assign values using variable_name=value. Access them using $variable_name or ${variable_name}.

Bash

#!/bin/bash
name="John Doe"
echo "Hello, $name!"

2.2. Input/Output

  • echo: Prints text to the console.
  • read: Reads input from the user.

Bash

#!/bin/bash
read -p "Enter your name: " name
echo "Your name is: $name"

  2.3. Conditional Statements (if, elif, else)

Control the flow of execution based on conditions.

Bash

 #!/bin/bash 
 read -p "Enter a number: " num
 if [ $num -gt 0 ]; then
   echo "Positive number."
 elif [ $num -lt 0 ]; then
   echo "Negative number."
 else
   echo "Zero."
 fi

2.4. Loops (for, while)

Repeat a block of code.

  • for loop: Iterates over a list of items.

Bash

 #!/bin/bash 
 for i in 1 2 3 4 5; do
   echo "Number: $i"
 done
  • while loop: Executes as long as a condition is true.

Bash

#!/bin/bash
count=1
 while [ $count -le5 ]; do
   echo "Count: $count"
   count=$((count + 1))
 done

 

3. Practical Scripting Examples

Here are the scripts from your previous requests, integrated into this chapter:

3.1. Reversing a Number

Bash

 #!/bin/bash
 read -p "Enter a number: " num
 reversed=""
 original_num=$num
 while [ $num -gt 0 ]; do
   digit=$((num % 10))
   reversed="$reversed$digit"
   num=$((num / 10))
 done
 echo "Original number: $original_num"
 echo "Reversed number: $reversed"

3.2. Displaying Username as Banner

Bash

#!/bin/bash
username=$(whoami)
 banner=$(banner "$username")
 if [[ -n "$banner" ]]; then
   echo "$banner"
 else
   echo "Error: banner command not found or failed."
 fi

3.3. Listing Directories

Bash

#!/bin/bash
for item in *; do
   if [ -d "$item" ]; then
     echo "$item"
   fi
 done

3.4. Using ls and more Based on File Type

Bash

 #!/bin/bash
 if [ $# -ne 1 ]; then
   echo "Usage: $0 "
   exit 1
 fi
 filename="$1"
 if [ -d "$filename" ]; then
   ls -l "$filename"
 elif [ -f "$filename" ]; then
   more "$filename"
 else
   echo "Error: '$filename' is not a file or directory."
   exit 1
 fi

 3.5. Copying/Overwriting a File

Bash

 #!/bin/bash
 if [ $# -ne 2 ]; then
   echo "Usage: $0 "
   exit 1
 fi
 source_file="$1"
 destination_file="$2"
 if [ ! -f "$source_file" ]; then
   echo "Error: Source file '$source_file' does not exist."
   exit 1
 fi
 cp "$source_file" "$destination_file"
 if [ $? -eq 0 ]; then
   echo "File '$source_file' copied to '$destination_file' successfully."
 else
   echo "Error: Failed to copy file '$source_file' to '$destination_file'."
   exit 1
 fi

 3.6. Word Length

Bash

 #!/bin/bash
 read -p "Enter a word: " word
 length=${#word}
 echo "The word '$word' is $length characters long."

3.7. Appending Line to File

Bash

#!/bin/sh 
if [ $# -ne 2 ]; then
   echo "Usage: $0 "
   exit 1
 fi
 filename="$1"
 line_to_append="$2"
 if [ ! -f "$filename" ]; then
   echo "Error: File '$filename' does not exist."
   exit 1
 fi
 echo "$line_to_append" >> "$filename"
 if [ $? -ne 0 ]; then
   echo "Error: Failed to append line to '$filename'."
   exit 1
 fi
 line_count=$(wc -l < "$filename")
 echo "Line appended successfully. Total lines in '$filename': $line_count"

 3.8. User UID and Login Count

Bash

 #!/bin/bash
if [ $# -ne 1 ]; then
echo "Usage: $0 "
exit 1
fi
username="$1"
uid=$(id -u "$username" 2>/dev/null)
if [ -z "$uid" ]; then
echo "Error: User '$username' not found."
exit 1
fi
login_count=$(lastb "$username" | wc -l)
successful_logins=$(last "$username" | wc -l)
total_logins=$((login_count + successful_logins))
echo "Username: $username"
echo "UID: $uid"
echo "Total Logins (successful and failed): $total_logins"
echo "Successful Logins: $successful_logins"
echo "Failed Logins: $login_count"

3.9. User Information from UID

Bash

#!/bin/bash
if [ $# -ne 1 ]; then
  echo "Usage: $0 "
  exit 1
fi
uid="$1"
username=$(getent passwd "$uid" | cut -d: -f1)
if [ -z "$username" ]; then
  echo "Error: UID '$uid' not found."
  exit 1
fi
fullname=$(getent passwd "$uid" | cut -d: -f5 | cut -d, -f1)
home_dir=$(getent passwd "$uid" | cut -d: -f6)
shell=$(getent passwd "$uid" | cut -d: -f7)
primary_group=$(getent group "$(getent passwd "$uid" | cut -d: -f4)" | cut -d: -f1)
secondary_groups=$(getent group | awk -F: '$4 ~ /'"$uid"'/ {print $1}')
echo "Username: $username"
echo "Full Name: $fullname"
echo "Home Directory: $home_dir"
echo "Shell: $shell"
echo "Primary Group: $primary_group"
if [ -n "$secondary_groups" ]; then
  echo "Secondary Groups: $secondary_groups"
fi

3.10. Mail Merge Facility

Bash

#!/bin/bash

# Mail Merge Script
# Usage: mail_merge.sh

# Check for correct number of arguments
if [ $# -ne 4 ]; then
  echo "Usage: $0 "
  exit 1
fi

TEMPLATE_FILE="$1"
DATA_FILE="$2"
SUBJECT="$3"
OUTPUT_DIR="$4"

# Check if template and data files exist
if [ ! -f "$TEMPLATE_FILE" ]; then
  echo "Error: Template file '$TEMPLATE_FILE' not found."
  exit 1
fi

if [ ! -f "$DATA_FILE" ]; then
  echo "Error: Data file '$DATA_FILE' not found."
  exit 1
fi

# Check if output directory exists, if not, create it
if [ ! -d "$OUTPUT_DIR" ]; then
  mkdir -p "$OUTPUT_DIR"
  fi

#Read data file line by line
while IFS=',' read -r name email address; do
  # Create output file name
  OUTPUT_FILE="$OUTPUT_DIR/mail_to_$email.txt"
  # Replace placeholders in template file
  cat "$TEMPLATE_FILE" | sed \
    -e "s/{{NAME}}/$name/g" \
    -e "s/{{EMAIL}}/$email/g" \
    -e "s/{{ADDRESS}}/$address/g" > "$OUTPUT_FILE"

# Send email (optional - requires mail command or similar)
# echo "Mail content generated in $OUTPUT_FILE"
# mail -s "$SUBJECT" "$email" < "$OUTPUT_FILE"

done < "$DATA_FILE"
echo "Mail merge completed. Output files generated in '$OUTPUT_DIR'."
exit 0

Explanation and Usage:

  1. Script Arguments:
    • <template_file>: The path to the template file containing placeholders like {{NAME}}, {{EMAIL}}, and {{ADDRESS}}.
    • <data_file>: The path to a CSV (comma-separated values) file containing the data to be merged. The first line of the CSV file should be name,email,address. Subsequent lines contain the data for each recipient.
    • <subject>: The subject line for the emails.
    • <output_dir>: The directory where the generated mail files will be saved.
  2. Error Handling:
    • The script checks if the correct number of arguments are provided.
    • It verifies that the template and data files exist.
    • It creates the output directory if it doesn’t already exist.
  3. Data Processing:
    • The while IFS=',' read -r name email address; do ... done < "$DATA_FILE" loop reads the data file line by line, splitting each line into the name, email, and address variables using commas as delimiters.
    • For each line, it creates an output file named mail_to_<email>.txt in the specified output directory.
    • The cat "$TEMPLATE_FILE" | sed ... > "$OUTPUT_FILE" command reads the template file and uses sed to replace the placeholders with the corresponding data from the current line.
  4. Optional Email Sending:
    • The commented-out mail command demonstrates how to send the generated emails. You’ll need to have the mail command (or a similar mail utility) installed on your system.
    • Uncomment the lines to enable email sending.

Example Template File (template.txt):

Dear {{NAME}},

This is a personalized message for you.

Your email address is: {{EMAIL}}
Your address is: {{ADDRESS}}

Sincerely,
The Team

Example Data File (data.csv):

Code snippet

name,email,address
John Doe,john.doe@example.com,123 Main St
Jane Smith,jane.smith@example.com,456 Oak Ave
Peter Jones,peter.jones@example.com,789 Pine Ln

How to Run the Script:

  1. Save the script to a file (e.g., mail_merge.sh).
  2. Make the script executable: chmod +x mail_merge.sh.
  3. Run the script: ./mail_merge.sh template.txt data.csv "Your Subject" output_mails.

This will generate three files in the output_mails directory: mail_to_john.doe@example.com.txt, mail_to_jane.smith@example.com.txt, and mail_to_peter.jones@example.com.txt.

Author

  • Dr. Anil Warbhe is a freelance technical consultant and a passionate advocate for simplifying complex technologies. His expertise lies in developing custom mobile applications, websites, and web applications, providing technical consultancy on server administration, and offering insightful perspectives on current tech trends through his writing.

    View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *