This guide is designed to take you from a beginner to a confident scripter by walking you through 25 common and practical Linux Bash script examples. Whether you are managing a personal project, a small business website, or a large-scale enterprise environment, mastering these scripts will provide a solid foundation for streamlining your operations. We will cover everything from basic “Hello, World!” scripts to more advanced examples involving loops, conditionals, and user input, equipping you with the skills to automate your workflow effectively.

Key Takeaways

  • Automation is Key: Bash scripting is essential for automating repetitive tasks in Linux, saving time, and reducing human error.
  • Start Simple: Begin with basic scripts like “Hello, World!” and displaying system information to understand fundamental concepts.
  • Master the Fundamentals: Core concepts like variables, user input, conditional statements (if-else), and loops (for, while) are the building blocks of all powerful scripts.
  • Practical Applications: This guide covers real-world examples, including file and directory management, system monitoring (disk space, memory), user management, and creating backups.
  • Interactive and Dynamic Scripts: Learn to create scripts that can accept user input, process command-line arguments, and perform different actions based on specific conditions.
  • Advanced Techniques: Explore more complex scripts that involve functions, process management, and parsing log files to handle sophisticated administrative tasks.

Getting Started: The Anatomy of a Bash Script

Before we dive into the examples, let’s quickly cover the basics of creating and running a Bash script.

A Bash script is a plain text file containing a series of commands. The first line of the script is crucial. it is called the “shebang” and it tells the system which interpreter to use to execute the file. For Bash scripts, this line is almost always:

#!/bin/bash

To create a script, you can use any text editor, like nano or vim. For example, to create your first script file, you would type:

nano first_script.sh

The .sh extension is a convention to identify shell scripts, though it is not strictly required.

After writing your script, you need to make it executable. The chmod command is used to change the permissions of a file.

chmod +x first_script.sh

Finally, to run the script, you execute it from your terminal like this:

./first_script.sh

The ./ tells the shell to look for the file in the current directory.

25 Common Bash Script Examples

Now, let’s get into the practical examples. We’ll start with the basics and gradually move to more complex scripts.

1. The Classic “Hello, World!”

Every programming journey begins with a “Hello, World!” example. This script simply prints the text to the terminal.

The Script:

#!/bin/bash

# This is a comment. The script will print “Hello, World!”

echo “Hello, World!”

How it Works:

  • #!/bin/bash: The shebang, defining the interpreter.
  • #: Lines starting with a hash are comments and are ignored by the interpreter. They are used for explaining the code.
  • echo: This is one of the most fundamental commands. It displays a line of text.

Use Case: This script is perfect for verifying that your environment is set up correctly and you understand the basic process of creating and running a script.

2. Using Variables to Store Information

Variables are used to store data that can be referenced later in the script. This makes scripts more dynamic and easier to read.

The Script:

#!/bin/bash

# Declare a variable

GREETING=”Hello, Elementor User!”

# Print the variable’s content

echo $GREETING

How it Works:

  • GREETING=”…”: We declare a variable named GREETING and assign it a string value. Note there are no spaces around the equals sign (=).
  • echo $GREETING: To access the value of a variable, you prefix its name with a dollar sign ($).

Use Case: Storing reusable pieces of information like usernames, file paths, or configuration settings. For instance, you could store your domain name in a variable for use in multiple commands.

3. Accepting User Input

Interactive scripts are incredibly useful. The read command allows you to capture input from the user and store it in a variable.

The Script:

#!/bin/bash

echo “What is your name?”

read USER_NAME

echo “Hello, $USER_NAME! Welcome.”

How it Works:

  • echo “What is your name?”: Prompts the user for information.
  • read USER_NAME: Pauses the script and waits for the user to type something and press Enter. The input is stored in the USER_NAME variable.

Use Case: Creating interactive tools, such as scripts that ask for a filename to process, a username to create, or a domain to configure.

4. Simple System Information Display

This script gathers and displays some basic information about your Linux system.

The Script:

#!/bin/bash

echo “— System Information —“

echo “Hostname: $(hostname)”

echo “Kernel Version: $(uname -r)”

echo “Uptime: $(uptime -p)”

echo “Current User: $(whoami)”

echo “————————–“

How it Works:

  • $(command): This is called command substitution. The shell executes the command inside the parentheses and replaces the $(…) with the command’s output.
  • hostname: Prints the system’s hostname.
  • uname -r: Prints the kernel release version.
  • uptime -p: Shows how long the system has been running in a “pretty” format.
  • whoami: Displays the current logged-in user.

Use Case: Quickly checking the status and identity of a server you have logged into. This is especially helpful when managing multiple servers.

5. Using Positional Arguments

Scripts can accept arguments directly from the command line when they are executed. These are called positional arguments.

The Script:

#!/bin/bash

# $1 refers to the first argument, $2 to the second, and so on.

echo “Hello, $1!”

echo “You are using the $2 theme.”

How to Run it:

./script.sh “Itamar” “Hello Theme”

Output:

Hello, Itamar!

You are using the Hello Theme.

How it Works:

  • $1, $2, $3, etc., are special variables that hold the command-line arguments. $0 holds the name of the script itself.

Use Case: Creating flexible tools that operate on user-provided data without prompting them interactively. For example, a script that takes a filename as an argument to perform an operation on it.

6. The if-else Statement for Conditional Logic

Conditional statements allow your script to make decisions and execute different blocks of code based on whether a certain condition is true or false.

The Script:

#!/bin/bash

echo “Enter a number:”

read NUM

if [ $NUM -gt 100 ]; then

  echo “That’s a big number!”

else

  echo “The number is 100 or less.”

fi

How it Works:

  • if [ condition ]; then … fi: This is the basic structure of an if statement.
  • [ $NUM -gt 100 ]: This is the condition being tested. The square brackets [] are an alias for the test command.
    • -gt: stands for “greater than”.
    • Other common numerical comparisons: -lt (less than), -eq (equal to), -ne (not equal to), -ge (greater than or equal to), -le (less than or equal to).
  • else: This block of code runs if the condition is false.

Use Case: Writing scripts that behave differently based on input or system state. For example, checking if a file exists before trying to read it.

7. Checking if a File Exists

A practical application of the if statement is checking for the existence of a file.

The Script:

#!/bin/bash

FILE_PATH=”/var/www/html/index.html”

if [ -f “$FILE_PATH” ]; then

    echo “File exists: $FILE_PATH”

else

    echo “File does not exist: $FILE_PATH”

fi

How it Works:

  • -f: This is a test operator that returns true if the specified path exists and is a regular file.
  • Other file-related operators: -d (checks if a directory exists), -e (checks if any file or directory exists), -s (checks if a file exists and is not empty).

Use Case: Essential for scripts that need to manipulate files. You can prevent errors by ensuring a file or directory exists before trying to copy, delete, or modify it.

8. The for Loop for Iteration

Loops are used to execute a block of code multiple times. A for loop is perfect for iterating over a list of items.

The Script:

#!/bin/bash

# Loop over a list of website names

for SITE in “elementor.com” “wordpress.org” “google.com”

do

  echo “Pinging $SITE…”

  ping -c 1 $SITE

done

echo “Loop finished.”

How it Works:

  • for SITE in …; do … done: The loop iterates through each item in the list (“elementor.com”, “wordpress.org”, “google.com”).
  • In each iteration, the current item is assigned to the variable SITE.
  • ping -c 1 $SITE: Pings the website just once (-c 1) to check for connectivity.

Use Case: Automating tasks that need to be performed on multiple items, such as backing up a list of databases, checking the status of several servers, or processing all files in a directory.

9. Creating a Simple Backup Script

This is a more practical example that combines variables, if statements, and commands to create a backup of a directory.

The Script:

#!/bin/bash

SOURCE_DIR=”/var/www/html”

BACKUP_DIR=”/mnt/backups/website”

TIMESTAMP=$(date +”%Y-%m-%d_%H-%M-%S”)

BACKUP_FILENAME=”website_backup_$TIMESTAMP.tar.gz”

# Check if backup directory exists, if not, create it

if [ ! -d “$BACKUP_DIR” ]; then

  echo “Backup directory not found. Creating it now…”

  mkdir -p “$BACKUP_DIR”

fi

# Create the compressed archive

echo “Creating backup of $SOURCE_DIR…”

tar -czf “$BACKUP_DIR/$BACKUP_FILENAME” “$SOURCE_DIR”

echo “Backup complete!”

echo “File created: $BACKUP_DIR/$BACKUP_FILENAME”

How it Works:

  • TIMESTAMP=$(date …): We use the date command to create a unique timestamp for our backup file. This prevents overwriting old backups.
  • if [ ! -d “$BACKUP_DIR” ]: The ! negates the condition, so this checks if the directory does not exist. The -d operator checks for a directory.
  • mkdir -p “$BACKUP_DIR”: Creates the directory. The -p flag ensures that it also creates any parent directories if they do not exist.
  • tar -czf …: This is the core command.
    • tar: The tape archive command, used for creating archives.
    • -c: Create a new archive.
    • -z: Compress the archive with gzip.
    • -f: Specifies the filename of the archive.

Use Case: This is a foundational script for any system administrator. You can schedule this script to run automatically using a cron job for regular, automated backups of your WordPress website.

10. while Loop for Reading a File Line by Line

A while loop continues as long as a certain condition is true. A common use case is reading a file line by line.

The Script:

#!/bin/bash

INPUT_FILE=”servers.txt”

# Create a sample file for demonstration

echo “server1.example.com” > $INPUT_FILE

echo “server2.example.com” >> $INPUT_FILE

echo “server3.example.com” >> $INPUT_FILE

echo “Reading servers from $INPUT_FILE…”

while IFS= read -r LINE

do

  echo “Processing server: $LINE”

done < “$INPUT_FILE”

How it Works:

  • while IFS= read -r LINE: This is the standard, safe way to read a file line by line in Bash.
    • read -r: The -r option prevents backslash escapes from being interpreted.
    • IFS=: IFS (Internal Field Separator) is set to empty to prevent leading/trailing whitespace from being trimmed.
  • done < “$INPUT_FILE”: This redirects the content of $INPUT_FILE into the while loop’s standard input.

Use Case: Processing log files, reading a list of users or domains from a text file to perform an action on each one.

11. case Statement for Menu-driven Scripts

A case statement is a cleaner way to handle multiple choices compared to a long chain of if-elif-else statements. It is ideal for creating simple menus.

The Script:

#!/bin/bash

echo “— MAIN MENU —“

echo “1. Display Disk Usage”

echo “2. Display Uptime”

echo “3. Display Logged-in Users”

echo “—————–“

echo “Please enter an option:”

read OPTION

case $OPTION in

  1)

    df -h

    ;;

  2)

    uptime

    ;;

  3)

    who

    ;;

  *)

    echo “Invalid option. Please choose 1, 2, or 3.”

    ;;

esac

How it Works:

  • case $OPTION in … esac: This is the structure of the case statement. It checks the value of $OPTION.
  • 1) … ;;: This is a pattern. If $OPTION matches 1, the commands until the ;; are executed.
  • *) … ;;: The * is a wildcard that matches anything. It acts as a default case for invalid input.

Use Case: Building simple command-line tools that offer the user a set of predefined actions to choose from.

12. Monitoring Disk Space and Sending an Alert

This script checks the disk usage of the root partition. If it exceeds a certain threshold, it sends an alert (in this case, just printing a message, but it could be an email).

The Script:

#!/bin/bash

THRESHOLD=90

CURRENT_USAGE=$(df / | grep / | awk ‘{ print $5 }’ | sed ‘s/%//g’)

if [ “$CURRENT_USAGE” -gt “$THRESHOLD” ]; then

  echo “WARNING: Root partition disk space is critically low!”

  echo “Current usage is at ${CURRENT_USAGE}%.”

  # Example of sending an email alert (requires mail server setup)

  # mail -s ‘Disk Space Alert’ [email protected] <<< “Root partition usage is at ${CURRENT_USAGE}%”

fi

How it Works:

  • df /: Shows the disk usage for the root filesystem (/).
  • grep /: Filters the output to get the line for the root partition.
  • awk ‘{ print $5 }’: Prints the 5th column of the line, which is the percentage used.
  • sed ‘s/%//g’: Removes the % symbol from the output so we have a clean number for comparison.
  • ${CURRENT_USAGE}: This is an alternative way to reference a variable, often used to avoid ambiguity.

Use Case: A critical monitoring script for any server. Run this with a cron job every hour to get early warnings about potential disk space issues, which is vital for services like Elementor Hosting.

13. Automating User Creation

This script automates the process of adding a new user to the system.

The Script:

#!/bin/bash

# This script must be run as root

if [ “$(id -u)” -ne 0 ]; then

  echo “This script must be run as root. Aborting.”

  exit 1

fi

echo “Enter username for the new account:”

read NEW_USER

# Check if the user already exists

if id “$NEW_USER” &>/dev/null; then

    echo “User ‘$NEW_USER’ already exists. Aborting.”

    exit 1

fi

useradd -m -s /bin/bash “$NEW_USER”

if [ $? -eq 0 ]; then

    echo “User ‘$NEW_USER’ created successfully.”

    echo “Please set a password for the new user:”

    passwd “$NEW_USER”

else

    echo “Error creating user ‘$NEW_USER’.”

    exit 1

fi

How it Works:

  • if [ “$(id -u)” -ne 0 ]: Checks if the current user’s ID is not 0. The root user always has a UID of 0. This ensures the script has the necessary permissions.
  • exit 1: Exits the script with a non-zero status code, indicating an error occurred.
  • id “$NEW_USER” &>/dev/null: This command checks if the user exists. &>/dev/null redirects both standard output and standard error to /dev/null, so we do not see any output from this command. We only care about its exit status.
  • useradd -m -s /bin/bash “$NEW_USER”: The command to add a user.
    • -m: Creates a home directory for the user.
    • -s /bin/bash: Sets the user’s default shell to Bash.
  • $?: This special variable holds the exit status of the last command executed. A status of 0 means success.
  • passwd “$NEW_USER”: Prompts to set the password for the new user.

Use Case: Streamlining the onboarding process for new team members or setting up service accounts for applications.

14. Defining and Using Functions

Functions allow you to group a set of commands together and give them a name. This helps in organizing your script and reusing code.

The Script:

#!/bin/bash

# Define a function to print a timestamp

log_message() {

  echo “$(date ‘+%Y-%m-%d %H:%M:%S’) – $1”

}

# Use the function

log_message “Starting the script.”

log_message “Performing a task…”

sleep 2

log_message “Task finished.”

log_message “Exiting the script.”

How it Works:

  • log_message() { … }: This defines a function named log_message.
  • $1: Inside a function, positional arguments ($1, $2, etc.) refer to the arguments passed to the function, not the script.
  • log_message “Starting the script.”: This calls the function and passes the string as the first argument.

Use Case: Creating modular and reusable code blocks. Functions are essential for writing clean, maintainable scripts of any significant length. For example, a backup script could have separate functions for check_disk_space(), create_archive(), and cleanup_old_backups().

15. Finding and Deleting Old Files

This script finds files in a specific directory that haven’t been modified in a certain number of days and deletes them. This is useful for cleaning up log or temporary directories.

The Script:

#!/bin/bash

TARGET_DIR=”/var/log”

DAYS_OLD=30

echo “Searching for files older than $DAYS_OLD days in $TARGET_DIR…”

# Use find to locate and delete the files.

# The -print option is for demonstration. Replace with -delete for actual deletion.

find “$TARGET_DIR” -type f -mtime +$DAYS_OLD -print

# To actually delete, use this command instead:

# find “$TARGET_DIR” -type f -mtime +$DAYS_OLD -delete

# echo “Deletion complete.”

How it Works:

  • find: A very powerful command for searching for files and directories.
  • “$TARGET_DIR”: The starting directory for the search.
  • -type f: Specifies to search only for files.
  • -mtime +$DAYS_OLD: The core condition. It finds files modified more than (+) $DAYS_OLD days ago.
  • -print: Prints the names of the files found.
  • -delete: This action tells find to delete the files it finds. Use this with caution!

Use Case: Automating cleanup tasks to prevent directories from filling up with old, unnecessary files, such as old backups, log files, or user-uploaded temporary files.

16. Checking the Status of a Web Service

This script uses curl to check if a website is responding correctly by looking for a 200 OK HTTP status code.

The Script:

#!/bin/bash

SITE_URL=”[https://elementor.com](https://elementor.com)”

STATUS_CODE=$(curl –write-out %{http_code} –silent –output /dev/null “$SITE_URL”)

if [ “$STATUS_CODE” -eq 200 ]; then

  echo “Site $SITE_URL is UP and running. (Status Code: $STATUS_CODE)”

else

  echo “Site $SITE_URL seems to be DOWN. (Status Code: $STATUS_CODE)”

fi

How it Works:

  • curl: A tool to transfer data from or to a server, using one of the supported protocols (HTTP, FTP, etc.).
  • –write-out %{http_code}: Tells curl to print only the HTTP status code to standard output.
  • –silent: Prevents curl from showing progress meters.
  • –output /dev/null: Redirects the actual page content to /dev/null so it is not displayed in the terminal.

Use Case: A simple but effective monitoring script to check if your websites are online. This can be integrated into a larger health-check script or run via a cron job to provide alerts.

17. Batch Renaming Files

This script renames all .txt files in the current directory to .log files.

The Script:

#!/bin/bash

# Create some dummy files

touch file1.txt file2.txt file3.txt

for FILENAME in *.txt

do

  # Use parameter expansion to get the filename without the extension

  BASE_NAME=”${FILENAME%.txt}”

  echo “Renaming $FILENAME to ${BASE_NAME}.log”

  mv “$FILENAME” “${BASE_NAME}.log”

done

How it Works:

  • for FILENAME in *.txt: The * is a wildcard that expands to match all files ending in .txt.
  • ${FILENAME%.txt}: This is a form of shell parameter expansion. It removes the shortest matching suffix (.txt) from the end of the variable’s value.
  • mv: The move command, which is also used for renaming files.

Use Case: Cleaning up file extensions, standardizing naming conventions, or preparing files for processing by another application.

18. Script to Process Multiple Command-Line Options (getopts)

For scripts that need to handle more complex options (like ls -l -a), getopts is the standard way to parse them.

The Script:

#!/bin/bash

# a: means option -a requires an argument

# v and h are simple flags

while getopts “a:vh” opt; do

  case $opt in

    a)

      echo “Argument for -a is $OPTARG”

      ;;

    v)

      echo “Verbose mode is ON”

      ;;

    h)

      echo “Usage: ./script.sh [-v] [-h] [-a argument]”

      exit 0

      ;;

    \?)

      echo “Invalid option: -$OPTARG” >&2

      exit 1

      ;;

  esac

done

How to Run it:

./script.sh -v -a “my_argument”

How it Works:

  • while getopts “a:vh” opt: This loop processes the options. The string “a:vh” defines the valid options. The colon after a means -a requires an argument.
  • $opt: In each iteration, getopts places the option character it found (e.g., a, v) into the opt variable.
  • $OPTARG: When an option requires an argument, getopts places that argument into the OPTARG variable.
  • \?: This case is triggered for an invalid option.

Use Case: Building professional-grade command-line utilities that offer flexibility and follow standard Linux command syntax. This is crucial for tools intended to be used by other people, perhaps other designers on your team.

19. Count the Number of Files in a Directory

A simple utility script to count how many files are in the current directory.

The Script:

#!/bin/bash

# ls -l: lists files in long format

# grep “^-“: filters for lines starting with ‘-‘, which indicates a regular file

# wc -l: counts the number of lines

FILE_COUNT=$(ls -l | grep “^-” | wc -l)

echo “There are $FILE_COUNT files in the current directory.”

How it Works: This script pipes the output of several commands together:

  1. ls -l: Lists the contents of the directory. For files, the line starts with -. For directories, it starts with d.
  2. grep “^-“: Filters this list, keeping only the lines that start with -, effectively selecting only the files.
  3. wc -l: Counts the number of lines in the filtered output, giving you the file count.

Use Case: Quick checks on directory contents, useful for scripts that need to verify if files have been generated or if a directory has the expected number of items.

20. Display a Random Quote

A fun script that shows how to work with arrays and generate random numbers.

The Script:

#!/bin/bash

QUOTES=(

  “The only way to do great work is to love what you do. – Steve Jobs”

  “Innovation distinguishes between a leader and a follower. – Steve Jobs”

  “Stay hungry, stay foolish. – Steve Jobs”

  “Your time is limited, so don’t waste it living someone else’s life. – Steve Jobs”

)

# Get the number of elements in the array

NUM_QUOTES=${#QUOTES[@]}

# Generate a random index

RANDOM_INDEX=$(( RANDOM % NUM_QUOTES ))

# Display the random quote

echo “— Daily Quote —“

echo “${QUOTES[$RANDOM_INDEX]}”

echo “——————-“

How it Works:

  • QUOTES=(…): This declares an array named QUOTES.
  • ${#QUOTES[@]}: This syntax gives the total number of elements in the array.
  • $RANDOM: This is a special shell variable that returns a different random integer each time it is accessed.
  • $(( … )): This is the syntax for arithmetic expansion.
  • RANDOM % NUM_QUOTES: The modulo operator (%) gives the remainder of a division. This is a common way to get a random number within a specific range (from 0 to NUM_QUOTES – 1).
  • ${QUOTES[$RANDOM_INDEX]}: This accesses an element of the array using its index.

Use Case: Adding a “message of the day” to your shell’s login screen or just for creating a bit of fun in the terminal.

21. Check Memory Usage

This script extracts the total, used, and free memory from the /proc/meminfo file.

The Script:

#!/bin/bash

echo “— Memory Usage —“

grep -E ‘MemTotal|MemFree|MemAvailable’ /proc/meminfo

echo “——————–“

How it Works:

  • /proc/meminfo: This is a virtual file in Linux that reports the amount of free and used memory (both physical and swap) on the system.
  • grep -E ‘MemTotal|MemFree|MemAvailable’:
    • grep -E: Enables extended regular expressions.
    • ‘…’: The pipe | acts as an “OR” operator, so this command finds lines containing MemTotal OR MemFree OR MemAvailable.

Use Case: Quick, scriptable way to check system memory status without the more complex output of commands like free or top.

22. Find the Largest Files in a Directory

This script is useful for finding out what is taking up all your disk space.

The Script:

#!/bin/bash

echo “Top 10 largest files/directories in the current directory:”

du -ah . | sort -rh | head -n 10

How it Works:

  • du -ah .: Calculates the disk usage (du) of all files and directories (a) in the current directory (.) in a human-readable format (h).
  • sort -rh: Sorts the output.
    • -r: Reverses the sort order (largest first).
    • -h: Sorts based on human-readable numbers (e.g., 2K, 1G).
  • head -n 10: Displays only the top 10 lines of the sorted output.

Use Case: An essential tool for disk space management and cleanup. When you get a disk space alert, this is one of the first commands to run.

23. Automate git pull for Multiple Repositories

If you work with multiple Git repositories, this script can save you a lot of time by pulling the latest changes for all of them at once.

The Script:

#!/bin/bash

# Add the paths to your git repositories here

REPO_DIRS=(

  “/path/to/your/first/repo”

  “/path/to/your/second/repo”

  “/path/to/another/project”

)

for DIR in “${REPO_DIRS[@]}”

do

  if [ -d “$DIR” ]; then

    echo “— Updating repository in $DIR —“

    cd “$DIR”

    git pull

    echo “————————————“

  else

    echo “WARNING: Directory does not exist: $DIR”

  fi

done

How it Works:

  • REPO_DIRS=(…): An array holding the paths to all your project directories.
  • for DIR in “${REPO_DIRS[@]}”: This syntax iterates over all elements in an array.
  • cd “$DIR”: Changes the current directory to the repository’s directory.
  • git pull: Fetches the latest changes from the remote repository.

Use Case: A massive time-saver for developers who work on multiple projects. Run this script at the start of your day to ensure all your local codebases are up to date.

24. A Simple Countdown Timer

This script creates a countdown timer that takes the number of seconds as an argument.

The Script:

#!/bin/bash

if [ -z “$1” ]; then

  echo “Usage: ./timer.sh <seconds>”

  exit 1

fi

SECONDS_LEFT=$1

while [ $SECONDS_LEFT -gt 0 ]; do

  echo -ne “Time remaining: $SECONDS_LEFT\033[0K\r”

  sleep 1

  SECONDS_LEFT=$((SECONDS_LEFT – 1))

done

echo “Time’s up!”

How it Works:

  • if [ -z “$1” ]: Checks if the first argument is empty (-z).
  • while [ $SECONDS_LEFT -gt 0 ]: The loop continues as long as there is time left.
  • echo -ne “…”:
    • -n: Do not output the trailing newline.
    • -e: Enable interpretation of backslash escapes.
  • \r: This is a carriage return. It moves the cursor back to the beginning of the line without moving down.
  • \033[0K: This is an ANSI escape code that clears the line from the cursor to the end.
  • sleep 1: Pauses the script for one second.
  • SECONDS_LEFT=$((SECONDS_LEFT – 1)): Decrements the counter.

Use Case: A useful utility for time management, or for scripts that need to pause for a specific duration before continuing.

25. Parse a Log File for Specific Errors

This script demonstrates how to parse a web server’s access log to find and count the number of “404 Not Found” errors.

The Script:

#!/bin/bash

LOG_FILE=”/var/log/nginx/access.log”

if [ ! -f “$LOG_FILE” ]; then

  echo “Log file not found: $LOG_FILE”

  exit 1

fi

# awk ‘$9 == “404“‘ selects lines where the 9th field (status code) is 404

# wc -l counts the resulting lines

ERROR_COUNT=$(awk ‘$9 == “404”‘ “$LOG_FILE” | wc -l)

echo “Found $ERROR_COUNT ‘404 Not Found’ errors in $LOG_FILE.”

How it Works:

  • awk ‘$9 == “404”‘ “$LOG_FILE”: awk is a powerful pattern scanning and processing language. This command processes the log file. In a standard Nginx access log, the HTTP status code is the 9th field (column). This command prints only the lines where this field is exactly “404”.
  • wc -l: Counts the lines, giving us the total number of 404 errors.

Use Case: Security and application monitoring. You can adapt this script to search for different status codes (like 500 server errors) or specific IP addresses to analyze traffic and identify potential issues. According to web creation expert Itamar Haim, “Automated log parsing is not a luxury. it is a necessity for maintaining the health and security of any modern web application.”

Frequently Asked Questions (FAQ)

1. What is the difference between sh and bash? sh (Bourne Shell) is the original Unix shell. bash (Bourne Again Shell) is an improved and more feature-rich version of sh. While many simple scripts can be run with sh, bash includes more advanced features like arrays, more robust programming constructs, and command-line editing. #!/bin/bash specifically requests the Bash interpreter, ensuring these advanced features are available.

2. How do I handle spaces in filenames or arguments? Always quote your variables. When you use a variable that might contain spaces, such as a filename, enclose it in double quotes (“). For example, use mv “$old_filename” “$new_filename” instead of mv $old_filename $new_filename. This prevents the shell from splitting the name at the spaces and treating it as multiple arguments.

3. What is the difference between single and double quotes? Double quotes (“) allow for variable and command substitution. The shell will replace $VARIABLE with its value. Single quotes (‘) treat every character literally. The shell will not perform any substitutions inside single quotes. Use single quotes when you want to print a literal dollar sign, for example: echo ‘The price is $5.’.

4. How do I debug a Bash script? You can run a script in debug mode using the -x option. This will print each command to the terminal before it is executed, showing you the flow of the script and the values of variables. Run it like this: bash -x your_script.sh.

5. What are cron jobs and how do they relate to scripting? A cron job is a time-based job scheduler in Unix-like operating systems. You can use it to schedule scripts to run automatically at a specific time and date. For example, you could schedule a backup script (like Example #9) to run every night at 2 AM. This is the primary way to achieve true, hands-off automation with Bash scripting.

6. Can I use Bash scripts on Windows? Yes. With the Windows Subsystem for Linux (WSL), you can run a full Linux environment, including Bash, directly on Windows 10 and 11. This provides a native way to run and develop Bash scripts without needing a separate virtual machine.

7. What does &>/dev/null mean? This is a form of output redirection. /dev/null is a special file, often called the “black hole,” that discards any data written to it. > redirects standard output (stdout), and 2> redirects standard error (stderr). The &> syntax is a shortcut in Bash to redirect both stdout and stderr to the same place. So, &>/dev/null means “run this command but throw away all of its output and any error messages.”

8. What is the purpose of exit 1? In shell scripting, programs return an exit code when they finish. By convention, an exit code of 0 means the program completed successfully. Any non-zero exit code (1, 2, 127, etc.) signifies an error. Using exit 1 in your script is a way to signal that the script terminated because something went wrong. This is useful for other scripts or monitoring tools that might be calling your script and need to know if it succeeded.

9. How can I make my scripts more secure?

  • Run with Least Privilege: Do not run scripts as root unless absolutely necessary.
  • Validate Input: Never trust user input. Sanitize and validate any data entered by a user before using it in commands, especially commands that modify the filesystem like rm.
  • Avoid Storing Passwords in Scripts: Use more secure methods like SSH keys for authentication or prompt for passwords interactively instead of hardcoding them.
  • Use set -e: Placing set -e at the top of your script will cause it to exit immediately if any command fails. This can prevent unexpected behavior.

10. Where can I learn more about Bash scripting? There are many excellent resources available online. The “Bash Guide for Beginners” on the Linux Documentation Project website is a great starting point. Websites like Stack Overflow have answers to almost any specific question you might have. For more structured learning, you can also check out various tutorials and video courses.