How to Conditionally Send Email from Command Line Based on Empty Body Content in Linux Log Monitoring


2 views

When setting up log monitoring scripts, a common approach is to pipe grep results directly to the mail command:

grep "error" /var/log/syslog | mail -s "Error Alert" admin@example.com

This creates an annoying issue - even when no matching lines are found, an empty email still gets sent. The GNU Mailutils mail command doesn't provide a native option to suppress emails with empty bodies.

The solution involves checking if grep actually found anything before sending the email. Here's a robust approach using shell scripting:

output=$(grep "error" /var/log/syslog)
if [ -n "$output" ]; then
    echo "$output" | mail -s "Error Alert" admin@example.com
fi

For those preferring one-liners or different tools, consider these alternatives:

Using grep's -q flag:

grep -q "error" /var/log/syslog && grep "error" /var/log/syslog | mail -s "Error Alert" admin@example.com

Using mailx with body checking:

grep "error" /var/log/syslog | { read body; [ -n "$body" ] && { echo "$body" | mailx -s "Error Alert" admin@example.com; }; }

For production systems, you might want a more comprehensive solution that includes:

#!/bin/bash

LOG_FILE="/var/log/syslog"
SEARCH_TERM="error"
RECIPIENT="admin@example.com"
SUBJECT="Error Alert"
TEMP_FILE=$(mktemp)

grep "$SEARCH_TERM" "$LOG_FILE" > "$TEMP_FILE"

if [ -s "$TEMP_FILE" ]; then
    mail -s "$SUBJECT" "$RECIPIENT" < "$TEMP_FILE"
    # Optional: add timestamp logging
    echo "$(date): Sent alert for '$SEARCH_TERM'" >> /var/log/monitoring.log
fi

rm -f "$TEMP_FILE"

For more complex monitoring scenarios across multiple logs:

#!/bin/bash

LOGS=("/var/log/syslog" "/var/log/nginx/error.log")
RECIPIENT="admin@example.com"
SUBJECT_PREFIX="Alert:"

for log in "${LOGS[@]}"; do
    errors=$(grep -i "error\\|warning\\|critical" "$log" 2>/dev/null)
    if [ -n "$errors" ]; then
        echo "$errors" | mail -s "${SUBJECT_PREFIX} ${log##*/}" "$RECIPIENT"
    fi
done

For high-volume log files, these optimizations can help:

  • Use grep -m 10 to limit output to first 10 matches
  • Add --line-buffered flag for real-time monitoring
  • Consider logwatch or similar tools for enterprise environments

When automating log monitoring with command line tools, we often face this scenario:

grep "error" /var/log/app.log | mail -s "Alert" admin@example.com

The issue? This sends an email even when grep finds no matches, resulting in empty notification emails that clutter your inbox.

In production environments, empty notifications create noise and mask real issues. The ideal solution should:

  • Only trigger emails when grep finds matches
  • Maintain the original matched content
  • Work across different Unix-like systems

Method 1: Using if/else in Bash

This is the most straightforward approach:

LOG_CONTENT=$(grep "critical" /var/log/system.log)
if [ -n "$LOG_CONTENT" ]; then
    echo "$LOG_CONTENT" | mail -s "System Alert" ops@example.com
fi

Method 2: Using && Operator

A more concise one-liner:

grep "timeout" /var/log/network.log | \
    grep -q . && grep "timeout" /var/log/network.log | \
    mail -s "Network Issue" netadmin@example.com

Method 3: Using mailx with -E Flag

Some mail clients support empty detection:

grep "segfault" /var/log/app.log | mailx -E -s "Crash Report" dev@example.com

For more robust monitoring, consider this script template:

#!/bin/bash

LOG_FILE="/var/log/application.log"
PATTERN="Exception|Error|Fail"
RECIPIENT="alerts@company.com"
SUBJECT="Application Error Report"

# Check for matches and send email
MATCHES=$(grep -E "$PATTERN" "$LOG_FILE")
if [[ -n "$MATCHES" ]]; then
    echo "$MATCHES" | mail -s "$SUBJECT" "$RECIPIENT"
    # Optional: Archive the found errors
    echo "$(date): $MATCHES" >> /var/log/error_archive.log
fi

Consider these additional improvements:

# Only send if more than 5 errors occur
COUNT=$(grep -c "OOM" /var/log/kernel.log)
if [ "$COUNT" -gt 5 ]; then
    grep "OOM" /var/log/kernel.log | mail -s "Memory Crisis" root@localhost
fi

# Add context with surrounding lines
grep -A 2 -B 2 "panic" /var/log/system.log | \
    if [ $(wc -l) -gt 0 ]; then \
        mail -s "System Panic" admin@example.com; \
    fi

For complex monitoring needs, consider:

  • swaks: Feature-rich SMTP testing tool
  • mutt: Powerful command line MUA with good scripting support
  • sendmail: Direct SMTP injection when mail utils aren't available