Linux Condition Testing

LinuxLinuxBeginner
Practice Now

Introduction

In this lab, you will learn how to use Linux condition testing to automate system checks and validations. Linux provides the powerful test command that allows you to evaluate conditions and execute actions based on the results. Understanding how to use this command is essential for writing shell scripts that can make decisions and respond to different conditions.

Throughout this lab, you will work with various aspects of the test command, including file testing, string comparison, and numeric evaluation. By the end of this session, you will be able to write scripts that can perform automated checks on your system and help maintain its integrity.

Understanding the Test Command Basics

The test command in Linux is a crucial tool for evaluating conditions in shell scripts. It allows you to check file properties, compare strings, evaluate numeric values, and more. When the condition being tested is true, test returns a zero exit status; otherwise, it returns a non-zero exit status.

Let's start with the basics. First, navigate to your project directory:

cd ~/project

The test command can be written in two ways:

  1. Using the word test followed by the condition
  2. Using square brackets [ ] around the condition

Let's try both methods to check if a directory exists:

## Method 1: Using the word 'test'
test -d ~/project && echo "The project directory exists."

## Method 2: Using square brackets
[ -d ~/project ] && echo "The project directory exists."

You should see the following output for both commands:

The project directory exists.

The -d option checks if a directory exists. The && operator is used to execute the echo command only if the test condition is true.

Some common file test options include:

  • -d file: True if file exists and is a directory
  • -e file: True if file exists
  • -f file: True if file exists and is a regular file
  • -r file: True if file exists and is readable
  • -w file: True if file exists and is writable
  • -x file: True if file exists and is executable
  • -s file: True if file exists and has a size greater than zero

Let's create a test file and check its properties:

## Create a test file
echo "Hello, Linux condition testing!" > test_file.txt

## Check if the file exists
test -e test_file.txt && echo "The file exists."

## Check if the file is readable
[ -r test_file.txt ] && echo "The file is readable."

## Check if the file is empty
[ -s test_file.txt ] && echo "The file is not empty."

These commands should produce the following output:

The file exists.
The file is readable.
The file is not empty.

Now, let's create a simple shell script that uses the test command to check if a file exists, and if not, create it:

## Create a script file
cat > check_file.sh << 'EOF'
#!/bin/bash

FILENAME="status.txt"

if [ ! -e "$FILENAME" ]; then
  echo "File $FILENAME does not exist. Creating it now."
  echo "This is a status file." > "$FILENAME"
else
  echo "File $FILENAME already exists."
fi

## Display file content
echo "Content of $FILENAME:"
cat "$FILENAME"
EOF

## Make the script executable
chmod +x check_file.sh

## Run the script
./check_file.sh

When you run the script, you should see output similar to:

File status.txt does not exist. Creating it now.
Content of status.txt:
This is a status file.

If you run the script again, you'll see:

File status.txt already exists.
Content of status.txt:
This is a status file.

This demonstrates how to use the test command to check file existence and take different actions based on the result.

Testing String Conditions

In this step, you will learn how to use the test command to compare strings. This is useful when you need to validate user input, check environment variables, or make decisions based on text content.

The common string comparison operators include:

  • ==: Equal to
  • !=: Not equal to
  • -z: True if the string is empty
  • -n: True if the string is not empty

Let's start by testing different string conditions:

## Test if two strings are equal
str1="linux"
str2="linux"
[ "$str1" == "$str2" ] && echo "The strings are equal."

## Test if two strings are different
str3="ubuntu"
[ "$str1" != "$str3" ] && echo "The strings are different."

## Test if a string is empty
empty_str=""
[ -z "$empty_str" ] && echo "The string is empty."

## Test if a string is not empty
[ -n "$str1" ] && echo "The string is not empty."

The output should be:

The strings are equal.
The strings are different.
The string is empty.
The string is not empty.

Now, let's create a script that asks for a password and checks if it meets certain criteria:

## Create a password validation script
cat > password_check.sh << 'EOF'
#!/bin/bash

echo "Enter a password:"
read -s password

## Check if password is empty
if [ -z "$password" ]; then
  echo "Error: Password cannot be empty."
  exit 1
fi

## Check password length
if [ ${#password} -lt 8 ]; then
  echo "Error: Password must be at least 8 characters long."
  exit 1
fi

## Check if password contains the word "password"
if [[ "$password" == *password* ]]; then
  echo "Error: Password cannot contain the word 'password'."
  exit 1
fi

echo "Password is valid!"
EOF

## Make the script executable
chmod +x password_check.sh

## Run the script
echo "You can test the script by running: ./password_check.sh"

Try running the script with different passwords to see how it validates input:

## Test with a short password
echo "short" | ./password_check.sh

## Test with a password containing "password"
echo "mypassword123" | ./password_check.sh

## Test with a valid password
echo "SecurePass123" | ./password_check.sh

The first two tests should fail, while the third one should succeed.

Let's create another script that processes system status based on a text input:

## Create a system status script
cat > system_status.sh << 'EOF'
#!/bin/bash

echo "Enter system status (normal, warning, critical):"
read status

if [ -z "$status" ]; then
  echo "No status provided. Assuming normal operation."
  status="normal"
fi

case "$status" in
  "normal")
    echo "System is operating normally. No action required."
    ;;
  "warning")
    echo "Warning: System requires attention. Check log files."
    ;;
  "critical")
    echo "CRITICAL: Immediate action required! System stability at risk."
    ;;
  *)
    echo "Unknown status: $status. Please use normal, warning, or critical."
    ;;
esac
EOF

## Make the script executable
chmod +x system_status.sh

## Run the script
echo "You can test the script by running: ./system_status.sh"

Try running the script with different status inputs:

## Test with "normal" status
echo "normal" | ./system_status.sh

## Test with "warning" status
echo "warning" | ./system_status.sh

## Test with "critical" status
echo "critical" | ./system_status.sh

## Test with an invalid status
echo "unstable" | ./system_status.sh

## Test with empty input
echo "" | ./system_status.sh

Each input should produce different output based on the conditional logic in the script.

Testing Numeric Conditions

In this step, you will learn how to use the test command for numeric comparisons. This is useful for checking resource usage, validating user input, or making decisions based on numeric values.

The common numeric comparison operators include:

  • -eq: Equal to
  • -ne: Not equal to
  • -lt: Less than
  • -le: Less than or equal to
  • -gt: Greater than
  • -ge: Greater than or equal to

Let's start with some basic numeric comparisons:

## Compare two numbers
num1=10
num2=20

## Equal to
[ $num1 -eq 10 ] && echo "$num1 is equal to 10"

## Not equal to
[ $num1 -ne $num2 ] && echo "$num1 is not equal to $num2"

## Less than
[ $num1 -lt $num2 ] && echo "$num1 is less than $num2"

## Greater than
[ $num2 -gt $num1 ] && echo "$num2 is greater than $num1"

## Less than or equal to
[ $num1 -le 10 ] && echo "$num1 is less than or equal to 10"

## Greater than or equal to
[ $num2 -ge 20 ] && echo "$num2 is greater than or equal to 20"

The output should look like:

10 is equal to 10
10 is not equal to 20
10 is less than 20
20 is greater than 10
10 is less than or equal to 10
20 is greater than or equal to 20

Now, let's create a script that checks disk space and alerts when it's below a certain threshold:

## Create a disk space check script
cat > disk_check.sh << 'EOF'
#!/bin/bash

## Get disk usage percentage (removing the % sign)
DISK_USAGE=$(df -h / | grep / | awk '{print $5}' | sed 's/%//')

## Set thresholds
WARNING_THRESHOLD=70
CRITICAL_THRESHOLD=90

echo "Current disk usage: $DISK_USAGE%"

if [ $DISK_USAGE -ge $CRITICAL_THRESHOLD ]; then
  echo "CRITICAL: Disk usage is critically high!"
  echo "Action: Clean up unnecessary files immediately."
elif [ $DISK_USAGE -ge $WARNING_THRESHOLD ]; then
  echo "WARNING: Disk usage is getting high."
  echo "Action: Consider cleaning up some files soon."
else
  echo "OK: Disk usage is normal."
  echo "No action required."
fi
EOF

## Make the script executable
chmod +x disk_check.sh

## Run the script
./disk_check.sh

The script will display the current disk usage and output a different message based on how full the disk is.

Let's create another script that simulates a temperature monitoring system:

## Create a temperature monitoring script
cat > temp_monitor.sh << 'EOF'
#!/bin/bash

## Function to generate a random temperature between 15 and 35
generate_temp() {
  echo $((RANDOM % 21 + 15))
}

## Generate random temperature
TEMP=$(generate_temp)
echo "Current temperature: ${TEMP}ยฐC"

## Temperature thresholds
MIN_TEMP=18
MAX_TEMP=26

if [ $TEMP -lt $MIN_TEMP ]; then
  echo "Action: Increase heating. Temperature is below minimum threshold."
elif [ $TEMP -gt $MAX_TEMP ]; then
  echo "Action: Activate cooling. Temperature is above maximum threshold."
else
  echo "Status: Temperature is within acceptable range."
fi

## Additional check for extreme temperatures
if [ $TEMP -ge 30 ]; then
  echo "WARNING: Temperature is very high. Check cooling systems."
fi
if [ $TEMP -le 17 ]; then
  echo "WARNING: Temperature is very low. Check heating systems."
fi
EOF

## Make the script executable
chmod +x temp_monitor.sh

## Run the script
./temp_monitor.sh

Each time you run this script, it will generate a random temperature and respond accordingly. Try running it multiple times to see different outcomes:

## Run the temperature monitor script multiple times
./temp_monitor.sh
./temp_monitor.sh
./temp_monitor.sh

These examples demonstrate how to use numeric conditions to monitor system parameters and take appropriate actions based on threshold values.

Combining Conditions with Logical Operators

In this step, you will learn how to combine multiple conditions using logical operators. This is essential for creating complex decision-making logic in your scripts.

The three main logical operators are:

  • && (AND): True if both conditions are true
  • || (OR): True if at least one condition is true
  • ! (NOT): True if the condition is false

Let's start with some basic examples:

## Create a test file
touch test_file.txt
chmod 644 test_file.txt

## AND operator - both conditions must be true
[ -f test_file.txt ] && [ -r test_file.txt ] && echo "The file exists and is readable."

## OR operator - at least one condition must be true
[ -x test_file.txt ] || [ -w test_file.txt ] && echo "The file is either executable or writable."

## NOT operator - inverts the condition
[ ! -x test_file.txt ] && echo "The file is not executable."

## Combining multiple operators
[ -f test_file.txt ] && [ -r test_file.txt ] && [ ! -x test_file.txt ] && echo "The file exists, is readable, but is not executable."

You should see output similar to:

The file exists and is readable.
The file is either executable or writable.
The file is not executable.
The file exists, is readable, but is not executable.

The test command also allows you to combine conditions within a single set of brackets using these operators:

  • -a (AND)
  • -o (OR)

For example:

## AND within a single test command
[ -f test_file.txt -a -r test_file.txt ] && echo "The file exists and is readable."

## OR within a single test command
[ -x test_file.txt -o -w test_file.txt ] && echo "The file is either executable or writable."

Let's create a more complex script that checks system resources:

## Create a system resource check script
cat > resource_check.sh << 'EOF'
#!/bin/bash

echo "Checking system resources..."

## Check memory usage
MEM_THRESHOLD=80
MEM_USED=$(free | grep Mem | awk '{print int($3/$2 * 100)}')

echo "Memory usage: ${MEM_USED}%"

## Check disk space
DISK_THRESHOLD=70
DISK_USED=$(df -h / | grep / | awk '{print $5}' | sed 's/%//')

echo "Disk usage: ${DISK_USED}%"

## Check CPU load (1-minute average)
LOAD_THRESHOLD=1.0
CPU_LOAD=$(cat /proc/loadavg | awk '{print $1}')

echo "CPU load average: ${CPU_LOAD}"

## Combined condition checking
if [ $MEM_USED -gt $MEM_THRESHOLD ] && [ $DISK_USED -gt $DISK_THRESHOLD ]; then
  echo "CRITICAL: Both memory and disk usage are high!"
  echo "Action: Free up resources immediately."
elif [ $MEM_USED -gt $MEM_THRESHOLD ] || [ $DISK_USED -gt $DISK_THRESHOLD ]; then
  echo "WARNING: Either memory or disk usage is high."
  echo "Action: Monitor system closely."
else
  echo "OK: Memory and disk usage are within acceptable limits."
fi

## Check if load is numeric before comparing
if [[ $CPU_LOAD =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
  ## We need to use bc for floating point comparison
  if (( $(echo "$CPU_LOAD > $LOAD_THRESHOLD" | bc -l) )); then
    echo "WARNING: CPU load is high. Check for resource-intensive processes."
  else
    echo "OK: CPU load is normal."
  fi
else
  echo "Error: Could not parse CPU load value."
fi
EOF

## Make the script executable
chmod +x resource_check.sh

## Run the script
./resource_check.sh

This script checks memory usage, disk space, and CPU load, then provides different outputs based on combinations of these conditions.

Finally, let's create a script that validates user input with multiple conditions:

## Create an input validation script
cat > validate_input.sh << 'EOF'
#!/bin/bash

echo "Enter a username (lowercase letters only, 3-8 characters):"
read username

echo "Enter your age (must be 18 or older):"
read age

## Username validation
is_valid_username=true

## Check if username is empty
if [ -z "$username" ]; then
  echo "Error: Username cannot be empty."
  is_valid_username=false
fi

## Check username length
if [ ${#username} -lt 3 ] || [ ${#username} -gt 8 ]; then
  echo "Error: Username must be between 3 and 8 characters."
  is_valid_username=false
fi

## Check if username contains only lowercase letters
if [[ ! "$username" =~ ^[a-z]+$ ]]; then
  echo "Error: Username must contain only lowercase letters."
  is_valid_username=false
fi

## Age validation
is_valid_age=true

## Check if age is a number
if [[ ! "$age" =~ ^[0-9]+$ ]]; then
  echo "Error: Age must be a number."
  is_valid_age=false
fi

## Check if age is at least 18
if [ "$is_valid_age" = true ] && [ $age -lt 18 ]; then
  echo "Error: You must be at least 18 years old."
  is_valid_age=false
fi

## Final validation
if [ "$is_valid_username" = true ] && [ "$is_valid_age" = true ]; then
  echo "Registration successful!"
  echo "Welcome, $username. Your account has been created."
else
  echo "Registration failed. Please correct the errors and try again."
fi
EOF

## Make the script executable
chmod +x validate_input.sh

## Run the script
echo "You can test the script by running: ./validate_input.sh"

Try running the script with different inputs to see how the combined conditions work together to validate user input:

## Test with valid input
echo -e "john\n25" | ./validate_input.sh

## Test with invalid username (too short)
echo -e "jo\n25" | ./validate_input.sh

## Test with invalid username (contains uppercase)
echo -e "John\n25" | ./validate_input.sh

## Test with invalid age (under 18)
echo -e "john\n17" | ./validate_input.sh

## Test with invalid age (not a number)
echo -e "john\nabc" | ./validate_input.sh

These examples demonstrate how to combine multiple conditions to create complex validation logic in your scripts.

Creating a Comprehensive System Monitoring Script

In this final step, you will combine everything you've learned to create a comprehensive system monitoring script. This script will check various system parameters and provide a summary report.

Let's create a script that monitors multiple system aspects:

## Create a system monitoring script
cat > system_monitor.sh << 'EOF'
#!/bin/bash

echo "========================================"
echo "    System Monitoring Report"
echo "    $(date)"
echo "========================================"
echo

## 1. Check if important system files exist
echo "1. System Files Check:"
important_files=("/etc/passwd" "/etc/hosts" "/etc/resolv.conf")
all_files_exist=true

for file in "${important_files[@]}"; do
  if [ -e "$file" ]; then
    echo "   [OK] $file exists"
    
    ## Check if file is empty
    if [ ! -s "$file" ]; then
      echo "   [WARNING] $file is empty"
    fi
    
    ## Check if file is readable
    if [ ! -r "$file" ]; then
      echo "   [WARNING] $file is not readable"
    fi
  else
    echo "   [ERROR] $file does not exist"
    all_files_exist=false
  fi
done

if [ "$all_files_exist" = true ]; then
  echo "   All system files are present."
else
  echo "   Some system files are missing. Check the errors above."
fi
echo

## 2. Check disk space
echo "2. Disk Space Check:"
disk_usage=$(df -h / | grep / | awk '{print $5}' | sed 's/%//')
echo "   Root partition usage: ${disk_usage}%"

if [ $disk_usage -ge 90 ]; then
  echo "   [CRITICAL] Disk usage is critically high!"
elif [ $disk_usage -ge 70 ]; then
  echo "   [WARNING] Disk usage is getting high."
else
  echo "   [OK] Disk usage is normal."
fi
echo

## 3. Check memory usage
echo "3. Memory Usage Check:"
mem_total=$(free -m | grep Mem | awk '{print $2}')
mem_used=$(free -m | grep Mem | awk '{print $3}')
mem_percentage=$((mem_used * 100 / mem_total))

echo "   Memory usage: ${mem_percentage}% (${mem_used}MB used out of ${mem_total}MB)"

if [ $mem_percentage -ge 90 ]; then
  echo "   [CRITICAL] Memory usage is critically high!"
elif [ $mem_percentage -ge 70 ]; then
  echo "   [WARNING] Memory usage is getting high."
else
  echo "   [OK] Memory usage is normal."
fi
echo

## 4. Check for active processes
echo "4. Process Check:"
critical_processes=("sshd" "cron")
for process in "${critical_processes[@]}"; do
  if pgrep -x "$process" > /dev/null; then
    echo "   [OK] $process is running"
  else
    echo "   [ERROR] $process is not running"
  fi
done
echo

## 5. Check system load
echo "5. System Load Check:"
load_1min=$(cat /proc/loadavg | awk '{print $1}')
load_5min=$(cat /proc/loadavg | awk '{print $2}')
load_15min=$(cat /proc/loadavg | awk '{print $3}')

echo "   Load average: $load_1min (1 min), $load_5min (5 min), $load_15min (15 min)"

## Determine number of CPU cores
num_cores=$(grep -c ^processor /proc/cpuinfo)
load_threshold=$(echo "scale=2; $num_cores * 0.7" | bc)

if (( $(echo "$load_1min > $load_threshold" | bc -l) )); then
  echo "   [WARNING] High load detected. The system might be under stress."
else
  echo "   [OK] System load is normal."
fi
echo

## 6. Check for recent failed login attempts
echo "6. Security Check:"
if [ -f /var/log/auth.log ]; then
  failed_logins=$(grep "Failed password" /var/log/auth.log | wc -l)
  echo "   Failed login attempts: $failed_logins"
  
  if [ $failed_logins -gt 10 ]; then
    echo "   [WARNING] High number of failed login attempts detected."
  else
    echo "   [OK] Normal login activity."
  fi
else
  echo "   [INFO] Cannot check login attempts (auth.log not accessible)"
fi
echo

## 7. Summary
echo "7. System Status Summary:"
critical_count=$(grep -c "\[CRITICAL\]" <<< "$(cat /dev/stdin)")
warning_count=$(grep -c "\[WARNING\]" <<< "$(cat /dev/stdin)")
error_count=$(grep -c "\[ERROR\]" <<< "$(cat /dev/stdin)")

if [ $critical_count -gt 0 ]; then
  echo "   [CRITICAL] System has critical issues that need immediate attention!"
elif [ $warning_count -gt 0 ] || [ $error_count -gt 0 ]; then
  echo "   [WARNING] System has some issues that should be addressed soon."
else
  echo "   [OK] System is operating normally. No significant issues detected."
fi

echo
echo "========================================"
echo "    End of System Monitoring Report"
echo "========================================"
EOF

## Make the script executable
chmod +x system_monitor.sh

## Run the script
./system_monitor.sh

This comprehensive script performs the following checks:

  1. Verifies if important system files exist and are readable
  2. Checks disk space usage
  3. Monitors memory usage
  4. Confirms critical processes are running
  5. Evaluates system load
  6. Examines security logs for failed login attempts
  7. Provides an overall system status summary

The output will vary depending on your system's current state, but it will provide a comprehensive overview of your system's health.

To make this script even more useful, you could:

  1. Schedule it to run periodically using cron
  2. Configure it to send alerts via email when critical issues are detected
  3. Add more specific checks relevant to your system

Let's create a simpler version that you can schedule to run periodically:

## Create a simplified monitoring script for scheduling
cat > daily_check.sh << 'EOF'
#!/bin/bash

## Set up log file
LOG_FILE="/tmp/system_check_$(date +%Y%m%d).log"

## Start logging
echo "System Check: $(date)" > $LOG_FILE
echo "--------------------------------" >> $LOG_FILE

## Check disk space
disk_usage=$(df -h / | grep / | awk '{print $5}' | sed 's/%//')
echo "Disk usage: ${disk_usage}%" >> $LOG_FILE

if [ $disk_usage -ge 90 ]; then
  echo "CRITICAL: Disk usage is critically high!" >> $LOG_FILE
elif [ $disk_usage -ge 70 ]; then
  echo "WARNING: Disk usage is getting high." >> $LOG_FILE
else
  echo "OK: Disk usage is normal." >> $LOG_FILE
fi

## Check memory
mem_total=$(free -m | grep Mem | awk '{print $2}')
mem_used=$(free -m | grep Mem | awk '{print $3}')
mem_percentage=$((mem_used * 100 / mem_total))
echo "Memory usage: ${mem_percentage}%" >> $LOG_FILE

if [ $mem_percentage -ge 90 ]; then
  echo "CRITICAL: Memory usage is critically high!" >> $LOG_FILE
elif [ $mem_percentage -ge 70 ]; then
  echo "WARNING: Memory usage is getting high." >> $LOG_FILE
else
  echo "OK: Memory usage is normal." >> $LOG_FILE
fi

## Check for critical services
for service in sshd cron; do
  if pgrep -x "$service" > /dev/null; then
    echo "$service is running" >> $LOG_FILE
  else
    echo "WARNING: $service is not running" >> $LOG_FILE
  fi
done

## End log
echo "--------------------------------" >> $LOG_FILE
echo "Check completed at $(date)" >> $LOG_FILE

## Display log location
echo "System check completed. Log saved to $LOG_FILE"
EOF

## Make the script executable
chmod +x daily_check.sh

## Run the script
./daily_check.sh

To schedule this script to run daily, you would typically use the cron system. Here's how you would set it up:

## Show how to set up a cron job (don't actually create it in this lab environment)
echo "To schedule this script to run daily at 9 AM, you would use:"
echo "crontab -e"
echo "And add the line:"
echo "0 9 * * * /home/labex/project/daily_check.sh"

This demonstrates how the Linux condition testing commands you've learned can be applied to create practical system monitoring tools.

Summary

In this lab, you have learned how to use Linux condition testing to evaluate different types of conditions and make decisions based on the results. Here is a summary of what you have accomplished:

  1. You learned the basics of the test command and how to check file properties such as existence, readability, and size.

  2. You explored string comparison using operators like ==, !=, -z, and -n to validate input and make decisions based on text content.

  3. You worked with numeric comparisons using operators like -eq, -ne, -lt, -gt, -le, and -ge to evaluate numerical values.

  4. You combined multiple conditions using logical operators (&&, ||, !) to create complex decision-making logic.

  5. You applied all these techniques to create comprehensive system monitoring scripts that can check various system parameters and provide status reports.

These skills are fundamental to shell scripting and system administration in Linux. The ability to test conditions and take different actions based on the results allows you to create scripts that can automate tasks, validate input, handle errors, and monitor system health.

Some practical applications of what you've learned include:

  • Creating automated backup scripts that check for available space before proceeding
  • Developing input validation for user-facing scripts
  • Building system monitoring tools that alert administrators to potential issues
  • Automating routine system maintenance tasks with conditional logic

As you continue to work with Linux, you will find that condition testing is an essential part of almost every shell script you create or maintain.