Create and Execute Bash Scripts in RHEL

Red Hat Enterprise LinuxBeginner
Practice Now

Introduction

In this lab, you will learn to create and execute Bash scripts for RHEL system administration. You will begin by crafting simple scripts, then enhance them with system commands and make them executable. The lab progresses to using for loops for automating tasks like system information gathering and filtering command output with grep and regular expressions. Finally, you will build a comprehensive RHEL system information script, gaining practical skills in automating administrative tasks and leveraging powerful shell features.

This is a Guided Lab, which provides step-by-step instructions to help you learn and practice. Follow the instructions carefully to complete each step and gain hands-on experience. Historical data shows that this is a beginner level lab with a 82% completion rate. It has received a 99% positive review rate from learners.

Create and Execute a Simple Bash Script

In this step, you will learn how to create a basic Bash script and execute it. Bash scripts are plain text files containing a series of commands that the Bash shell can execute. They are powerful tools for automating repetitive tasks and combining multiple commands into a single executable unit.

First, you will create a new directory to store your scripts. It's good practice to organize your files, and placing scripts in a dedicated directory helps keep your home directory tidy.

  1. Create a directory for your scripts.
    Use the mkdir command to create a directory named scripts within your ~/project directory. This is where you will store your Bash scripts.

    mkdir ~/project/scripts

    There will be no direct output from this command if successful.

  2. Create your first Bash script file.
    Navigate into the newly created scripts directory and use the nano text editor to create a file named firstscript.sh. The .sh extension is a common convention for shell scripts, though not strictly required.

    cd ~/project/scripts
    nano firstscript.sh

    Inside the nano editor, you will see a blank screen.

  3. Add content to your script.
    Every Bash script should start with a "shebang" line, #!/usr/bin/bash. This line tells the operating system which interpreter to use for executing the script (in this case, Bash). After the shebang, you will add a simple echo command to print a message to the terminal.

    Type the following lines into the nano editor:

    #!/usr/bin/bash
    echo "Hello, LabEx! This is my first Bash script."

    Once you have entered the content, save the file by pressing Ctrl+O, then Enter to confirm the filename, and Ctrl+X to exit nano.

    Your terminal should return to the command prompt.

  4. Execute your script using the bash interpreter.
    You can execute a Bash script by explicitly telling the bash interpreter to run it. This method does not require the script to have executable permissions.

    bash firstscript.sh

    You should see the output of your script:

    Hello, LabEx! This is my first Bash script.

    This confirms that your script was created correctly and executed successfully.

Enhance Bash Script with System Commands and Make Executable

In this step, you will enhance your Bash script by adding more system commands and learn how to make the script directly executable. Making a script executable allows you to run it like any other command, without explicitly calling the bash interpreter.

  1. Navigate to your scripts directory.
    Ensure you are in the ~/project/scripts directory where you created firstscript.sh in the previous step.

    cd ~/project/scripts
  2. Edit firstscript.sh to include more system commands.
    You will now add commands to your script that display system information, such as block devices and filesystem free space. This demonstrates how scripts can automate the collection of system data.

    Open firstscript.sh using nano:

    nano firstscript.sh

    Modify the content of the file to match the following. This script will now:

    • Print a header for block device information.
    • Execute lsblk to list block devices.
    • Print a header for filesystem free space.
    • Execute df -h to display disk space usage in a human-readable format.
    #!/usr/bin/bash
    echo "Hello, LabEx! This is my first Bash script."
    echo "#####################################################"
    echo "LIST BLOCK DEVICES"
    echo "#####################################################"
    lsblk
    echo "#####################################################"
    echo "FILESYSTEM FREE SPACE STATUS"
    echo "#####################################################"
    df -h

    Save the file by pressing Ctrl+O, then Enter, and Ctrl+X to exit nano.

  3. Make the script executable.
    To run a script directly (e.g., ./firstscript.sh), you need to grant it executable permissions. The chmod command is used to change file permissions. +x adds execute permission for all users.

    chmod +x firstscript.sh

    There will be no direct output from this command if successful.

  4. Execute the script directly.
    Now that the script is executable, you can run it by specifying its path. Since it's in your current directory, you use ./ followed by the script name.

    ./firstscript.sh

    You should see output similar to this, combining your initial message with the output of lsblk and df -h:

    Hello, LabEx! This is my first Bash script.
    #####################################################
    LIST BLOCK DEVICES
    #####################################################
    NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    loop0         7:0    0 10.2G  1 loop /
    loop1         7:1    0  200M  1 loop /usr/local/bin
    loop2         7:2    0  200M  1 loop /usr/local/go
    loop3         7:3    0  200M  1 loop /usr/local/java
    loop4         7:4    0  200M  1 loop /usr/local/node
    loop5         7:5    0  200M  1 loop /usr/local/python
    #####################################################
    FILESYSTEM FREE SPACE STATUS
    #####################################################
    Filesystem      Size  Used Avail Use% Mounted on
    overlay          10G  4.0G  6.1G  40% /
    tmpfs            64M     0   64M   0% /dev
    tmpfs           7.8G     0  7.8G   0% /sys/fs/cgroup
    shm              64M     0   64M   0% /dev/shm
    /dev/loop0       10G  4.0G  6.1G  40% /
    tmpfs           7.8G     0  7.8G   0% /proc/asound
    tmpfs           7.8G     0  7.8G   0% /proc/acpi
    tmpfs           7.8G     0  7.8G   0% /proc/scsi
    tmpfs           7.8G     0  7.8G   0% /sys/firmware

    The exact output for lsblk and df -h may vary slightly depending on the specific environment, but the structure and presence of the commands' output should be similar.

Use For Loops to Automate Hostname Retrieval on RHEL Servers

In this step, you will learn about for loops in Bash and how to use them to automate tasks across multiple servers. for loops are fundamental control flow statements that allow you to execute a block of code repeatedly for each item in a list. This is particularly useful for managing multiple systems efficiently.

For this exercise, we will demonstrate the concept using localhost with different approaches to simulate working with multiple servers.

  1. Retrieve hostname using local commands.
    Before using a loop, let's see how you would typically get the hostname from the local system. We'll use different methods to demonstrate the concept.

    hostname
    hostname -f

    You should see output similar to this:

    684791f71c0e35fea6cc1243
    684791f71c0e35fea6cc1243

    This demonstrates that you can successfully retrieve hostname information using different options. Note that in this container environment, all hostname options return the same container ID.

  2. Create a for loop to automate hostname retrieval with different options.
    Now, let's use a for loop to perform different hostname commands more efficiently. The for loop will iterate over a list of hostname options, executing the hostname command with each option.

    for OPTION in "" "-f" "-s"; do
      echo "hostname ${OPTION}:"
      hostname ${OPTION}
      echo ""
    done

    Let's break down this command:

    • for OPTION in "" "-f" "-s";: This part initializes the loop. OPTION is a variable that will take on the value of each item in the list (empty string, -f, -s) during each iteration.
    • do: Marks the beginning of the commands to be executed in the loop.
    • echo "hostname ${OPTION}:";: This displays which option is being used.
    • hostname ${OPTION};: This is the command executed in each iteration. ${OPTION} expands to the current value of the OPTION variable.
    • echo "";: Adds a blank line for better readability.
    • done: Marks the end of the loop.

    You should see output similar to this:

    hostname :
    684791f71c0e35fea6cc1243
    
    hostname -f:
    684791f71c0e35fea6cc1243
    
    hostname -s:
    684791f71c0e35fea6cc1243

    This demonstrates the power of for loops in automating repetitive tasks with different parameters.

Create and Execute a Bash Script with For Loop for RHEL Servers

In this step, you will encapsulate the for loop you learned in the previous step into a Bash script. This allows you to save the automation logic and reuse it easily. You will also learn about the PATH environment variable and how to make your scripts accessible from any directory.

  1. Navigate to your scripts directory.
    Ensure you are in the ~/project/scripts directory.

    cd ~/project/scripts
  2. Create a new script for hostname retrieval.
    You will create a script named get_hostnames.sh that contains the for loop to retrieve hostname information using different options.

    Open get_hostnames.sh using nano:

    nano get_hostnames.sh

    Add the following content to the file:

    #!/usr/bin/bash
    ## This script retrieves hostname information using different options.
    
    for OPTION in "" "-f" "-s"; do
      echo "Getting hostname with option: ${OPTION}"
      hostname ${OPTION}
      echo "------------------------"
    done
    
    exit 0

    Save the file by pressing Ctrl+O, then Enter, and Ctrl+X to exit nano.

    Let's break down the new elements:

    • ## This script...: Lines starting with # are comments. They are ignored by the shell but are useful for documenting your script.
    • echo "Getting hostname with option: ${OPTION}": This line provides feedback during script execution, indicating which option is currently being used.
    • exit 0: This command explicitly exits the script with a status code of 0, which conventionally indicates success.
  3. Make the script executable.
    Just like in the previous step, you need to give your new script executable permissions.

    chmod +x get_hostnames.sh

    There will be no direct output from this command if successful.

  4. Execute the script from its current directory.
    Run the script to verify its functionality.

    ./get_hostnames.sh
     You should see output similar to this:
    
    Getting hostname with option:
    684791f71c0e35fea6cc1243
    ------------------------
    Getting hostname with option: -f
    684791f71c0e35fea6cc1243
    ------------------------
    Getting hostname with option: -s
    684791f71c0e35fea6cc1243
    ------------------------
  5. Understand the PATH environment variable.
    The PATH environment variable is a list of directories that the shell searches for executable commands. When you type a command like ls or grep, the shell looks in the directories listed in PATH to find the corresponding executable file.

    Display your current PATH variable:

    echo $PATH

    You will see a colon-separated list of directories. For example:

    /home/labex/.local/bin:/home/labex/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

    Notice that ~/project/scripts (or /home/labex/project/scripts) is not typically included in the default PATH. This is why you had to use ./get_hostnames.sh to execute your script.

  6. Add your scripts directory to the PATH (Optional, for future reference).
    While not strictly required for this lab step, it's common practice to add a personal bin or scripts directory to your PATH so you can run your custom scripts from any location. You can do this by adding a line like export PATH=$PATH:~/project/scripts to your ~/.bashrc or ~/.zshrc file. For this lab, we will continue to execute scripts by specifying their path.

Filter Command Output with Grep and Regular Expressions on RHEL

In this step, you will learn how to use the grep command with regular expressions to efficiently filter and extract specific information from command output and files. grep is a powerful utility for searching plain-text data sets for lines that match a regular expression. Regular expressions (regex) are sequences of characters that define a search pattern.

  1. Search for specific user and group information in system files.
    You will use grep to find information about the labex user and group from the /etc/passwd and /etc/group files. These files store user and group account information, respectively.

    First, let's look for the labex user entry in /etc/passwd:

    grep "labex" /etc/passwd

    Expected output:

    labex:x:1000:1000::/home/labex:/bin/bash

    Next, find the labex group entry in /etc/group:

    grep "labex" /etc/group

    Expected output:

    labex:x:1000:

    These commands demonstrate basic grep usage to find exact string matches.

  2. Filter lscpu output using grep and regular expressions.
    The lscpu command displays CPU architecture information. Often, you only need specific lines from its extensive output. You can use grep with a regular expression to filter for lines that start with "CPU".

    lscpu | grep '^CPU'

    Let's break down this command:

    • lscpu: Generates the CPU information.
    • |: This is a pipe, which takes the standard output of lscpu and feeds it as standard input to the grep command.
    • grep '^CPU': Searches for lines that start with the literal string "CPU". The ^ (caret) is a regular expression anchor that matches the beginning of a line.

    Expected output (may vary slightly based on environment):

    CPU op-mode(s):                     32-bit, 64-bit
    CPU(s):                             4
    CPU family:                         6
  3. Filter configuration files, ignoring comments and empty lines.
    Configuration files often contain comments (lines starting with #) and empty lines that are not relevant to the actual configuration. You can use grep with multiple patterns to exclude these lines. Let's demonstrate this with the /etc/passwd file.

    grep -v '^#' /etc/passwd | head -5

    Let's break down this command:

    • grep -v '^#' /etc/passwd: The -v option inverts the match, meaning it selects lines that do not match the pattern. ^# matches lines that start with a #. So, this part filters out comment lines.
    • |: Pipes the output of the first grep command to the next command.
    • head -5: Shows only the first 5 lines of the output.

    Expected output (showing user account entries without comments):

    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  4. Search for specific patterns in system files.
    You can use grep to search for specific patterns in various system files. Let's search for shell-related entries in the /etc/passwd file.

    grep "bash" /etc/passwd

    Expected output (showing users with bash shell):

    root:x:0:0:root:/root:/bin/bash
    labex:x:1000:1000::/home/labex:/bin/bash

    This command helps you identify users who have bash as their default shell.

Build a Comprehensive RHEL System Information Script

In this final step, you will combine all the concepts learned so far – Bash scripting, for loops, ssh for remote execution, and grep with regular expressions for filtering – to build a comprehensive script that gathers system information from multiple RHEL servers. The script will save the collected data to separate output files for each server.

  1. Navigate to your scripts directory.
    Ensure you are in the ~/project/scripts directory.

    cd ~/project/scripts
  2. Create a new script named system_info.sh.
    This script will gather system information using different approaches to demonstrate the concepts, and redirect the output to distinct files in your ~/project directory.

    Open system_info.sh using nano:

    nano system_info.sh

    Add the following content to the file:

    #!/usr/bin/bash
    
    ## Define variables for output directory
    OUT_DIR='/home/labex/project'
    
    ## Loop through different information gathering approaches
    for APPROACH in "basic" "detailed"; do
      OUTPUT_FILE="${OUT_DIR}/output-${APPROACH}.txt"
    
      echo "Gathering ${APPROACH} system information..."
      ## Clear previous output file or create a new one
      > "${OUTPUT_FILE}"
    
      ## Get hostname information
      echo "#### Hostname Information ###" >> "${OUTPUT_FILE}"
      if [ "${APPROACH}" = "basic" ]; then
        hostname >> "${OUTPUT_FILE}"
      else
        hostname -f >> "${OUTPUT_FILE}"
      fi
      echo "" >> "${OUTPUT_FILE}" ## Add a blank line for readability
    
      ## Get CPU information (only lines starting with CPU)
      echo "#### CPU Information ###" >> "${OUTPUT_FILE}"
      lscpu | grep '^CPU' >> "${OUTPUT_FILE}"
      echo "" >> "${OUTPUT_FILE}"
    
      ## Get system users with bash shell
      echo "#### Users with Bash Shell ###" >> "${OUTPUT_FILE}"
      grep "bash" /etc/passwd >> "${OUTPUT_FILE}"
      echo "" >> "${OUTPUT_FILE}"
    
      ## Get system information based on approach
      if [ "${APPROACH}" = "basic" ]; then
        echo "#### Basic System Info ###" >> "${OUTPUT_FILE}"
        uname -r >> "${OUTPUT_FILE}"
      else
        echo "#### Detailed System Info ###" >> "${OUTPUT_FILE}"
        uname -a >> "${OUTPUT_FILE}"
      fi
      echo "" >> "${OUTPUT_FILE}"
    
      echo "Information saved to ${OUTPUT_FILE}"
      echo "-----------------------------------------------------"
    done
    
    echo "Script execution complete."

    Save the file by pressing Ctrl+O, then Enter, and Ctrl+X to exit nano.

    Key elements of this script:

    • OUT_DIR='/home/labex/project': Variable is used to make the script more flexible and readable.
    • OUTPUT_FILE="${OUT_DIR}/output-${APPROACH}.txt": Constructs the output filename dynamically for each approach.
    • > "${OUTPUT_FILE}": This redirects the output of an empty command to the file, effectively clearing its content if it exists or creating it if it doesn't. This ensures a fresh file for each run.
    • >> "${OUTPUT_FILE}": This appends the output of the command to the specified file.
    • if [ "${APPROACH}" = "basic" ]; then ... else ... fi: Conditional statements that execute different commands based on the approach being used.
    • echo "#### Section Header ###": Adds clear headers to the output file for better organization.
  3. Make the script executable.

    chmod +x system_info.sh

    There will be no direct output from this command if successful.

  4. Execute the system_info.sh script.
    Run your comprehensive script. It will gather system information using different approaches and save the results to separate files.

    ./system_info.sh

    You should see output in your terminal indicating the script's progress:

    Gathering basic system information...
    Information saved to /home/labex/project/output-basic.txt
    -----------------------------------------------------
    Gathering detailed system information...
    Information saved to /home/labex/project/output-detailed.txt
    -----------------------------------------------------
    Script execution complete.
  5. Review the generated output files.
    Check the content of the output-basic.txt and output-detailed.txt files in your ~/project directory to verify that the script collected the information as expected.

    cat ~/project/output-basic.txt
    cat ~/project/output-detailed.txt

    The content of each file should be similar to this (actual values will vary):

    output-basic.txt:

    #### Hostname Information ###
    684791f71c0e35fea6cc1243
    
    #### CPU Information ###
    CPU op-mode(s):                     32-bit, 64-bit
    CPU(s):                             4
    CPU family:                         6
    
    #### Users with Bash Shell ###
    root:x:0:0:root:/root:/bin/bash
    labex:x:1000:1000::/home/labex:/bin/bash
    
    #### Basic System Info ###
    5.4.0-162-generic

    output-detailed.txt:

    #### Hostname Information ###
    684791f71c0e35fea6cc1243
    
    #### CPU Information ###
    CPU op-mode(s):                     32-bit, 64-bit
    CPU(s):                             4
    CPU family:                         6
    
    #### Users with Bash Shell ###
    root:x:0:0:root:/root:/bin/bash
    labex:x:1000:1000::/home/labex:/bin/bash
    
    #### Detailed System Info ###
    Linux 684791f71c0e35fea6cc1243 5.4.0-162-generic #179-Ubuntu SMP Mon Aug 14 08:51:31 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

    This final script demonstrates how you can combine various Bash features and Linux commands to create powerful automation tools for system administration tasks.

Summary

In this lab, you learned the fundamental steps of creating and executing Bash scripts for RHEL system administration. You began by setting up a dedicated directory for scripts and then crafted a simple Bash script, understanding the importance of the shebang line and using the echo command. You explored different methods of executing scripts, including directly with the bash interpreter and by making them executable.

Furthermore, you enhanced your scripting skills by incorporating system commands and automating tasks using for loops to gather system information with different approaches. You also learned how to filter command output effectively using grep and regular expressions, a crucial skill for parsing system information. Finally, you applied these concepts to build a comprehensive RHEL system information script, demonstrating how to combine various commands and scripting constructs to gather and present valuable system data.