Introduction to df
The df (disk free) command is a fundamental Unix/Linux utility for reporting file system disk space usage. It provides essential information about mounted file systems, including total size, used space, available space, and usage percentages. Understanding df thoroughly is crucial for system administration, capacity planning, and monitoring disk usage.
Key Concepts
- File Systems: Mounted partitions and their mount points
- Disk Usage: Total, used, and available space
- Inodes: File system metadata storage
- Human-Readable: Formatted output for easy understanding
- Local vs Remote: Can show both local and network file systems
1. Basic Usage
Simple Disk Space Reports
#!/bin/bash # Basic df command (shows all mounted file systems) df # Show specific file system df /home df /dev/sda1 # Show multiple file systems df /home /var /tmp # Human-readable format (with -h) df -h df --human-readable # Show in kilobytes (default) df -k # Show in megabytes df -m # Show in gigabytes df -h # Already human-readable, but can force specific df -B G # Show in gigabytes (GNU) # Examples echo "=== Disk Usage Report ===" df -h echo echo "=== Root Filesystem ===" df -h /
Common Examples
#!/bin/bash # Check root filesystem usage df -h / # Check home directory usage df -h /home # Check current directory's filesystem df -h . # Show all filesystems including tmpfs df -h -a # Exclude specific filesystem types df -h -x tmpfs -x devtmpfs # Include only specific types df -h -t ext4 -t xfs # Show with total df -h --total # Create a report cat << EOF System Disk Usage Report ======================= Date: $(date) Host: $(hostname) $(df -h) Top Usage: $(df -h | sort -k5 -r | head -5) EOF
2. Essential Options
Common Options Reference
#!/bin/bash # -a, --all: Include dummy file systems df -a # -h, --human-readable: Print sizes in human readable format df -h # -H: Human-readable but with powers of 1000 (SI) df -H # -k: Use 1K blocks df -k # -m: Use 1M blocks df -m # -B, --block-size: Specify block size df -B 1K df -B 1M df -B 1G # -t, --type: Limit to filesystem type df -t ext4 df -t xfs df -t tmpfs # -x, --exclude-type: Exclude filesystem type df -x tmpfs df -x devtmpfs # -T, --print-type: Print filesystem type df -T # -l, --local: Only show local filesystems df -l # --total: Show total df --total # -i, --inodes: Show inode information instead of blocks df -i # --sync: Sync before getting usage df --sync # -P, --portability: POSIX output format df -P # Combine options df -hT df -hl --total df -h -t ext4 -t xfs
Practical Option Combinations
#!/bin/bash # Comprehensive system view df -hT --total # Local filesystems only with types df -lhT # Check filesystems with >80% usage df -h | awk 'NR>1 {gsub(/%/,"",$5); if($5>80) print $0}' # Show inodes usage df -hi # Monitor specific mount points df -h / /home /var # Check network filesystems df -h -t nfs -t cifs # Format for monitoring df --output='source,fstype,size,used,avail,pcent,target' -h # Watch disk usage changes watch -n 60 df -h 3. Understanding Output
Column Explanations
#!/bin/bash # Standard df output df -h # Output columns: # Filesystem Size Used Avail Use% Mounted on # /dev/sda1 98G 45G 48G 49% / # With -T (filesystem type) df -hT # Filesystem Type Size Used Avail Use% Mounted on # /dev/sda1 ext4 98G 45G 48G 49% / # With -i (inodes) df -hi # Filesystem Inodes IUsed IFree IUse% Mounted on # /dev/sda1 6.5M 235K 6.3M 4% / # Parse specific columns df -h | awk '{print $1, $5, $6}' # Filesystem, Use%, Mount # Get usage percentage of root df / | awk 'NR==2 {print $5}' | tr -d '%' # Check if any filesystem is over threshold df -h | awk 'NR>1 && $5+0 > 90 {print "Warning: " $6 " is " $5 " full"}' Interpreting Values
#!/bin/bash # Reserved blocks (typically 5% for root) tune2fs -l /dev/sda1 | grep "Reserved block count" # Why used + avail != total? # - Reserved blocks for root # - Filesystem metadata # - Rounding in human-readable output # Calculate actual usage including reserved df_actual() { local fs="$1" df -k "$fs" | awk 'NR==2 { total=$2 used=$3 avail=$4 reserved = total - used - avail pct_used = (used/total)*100 pct_with_reserve = ((used+reserved)/total)*100 printf "Filesystem: %s\n", $1 printf "Total: %d KB\n", total printf "Used: %d KB (%.1f%%)\n", used, pct_used printf "Available: %d KB\n", avail printf "Reserved: %d KB (%.1f%%)\n", reserved, (reserved/total)*100 }' } # Usage df_actual / 4. Working with Different Filesystem Types
Filtering by Type
#!/bin/bash # List all available filesystem types cat /proc/filesystems # Show only ext4 filesystems df -t ext4 -h # Show only XFS filesystems df -t xfs -h # Show only tmpfs (temporary filesystems) df -t tmpfs -h # Exclude pseudo filesystems df -x tmpfs -x devtmpfs -x squashfs -h # Show network filesystems df -t nfs -t nfs4 -t cifs -h # Multiple types df -t ext4 -t xfs -t btrfs -h # Usage example echo "=== Local Filesystems ===" df -l -h echo -e "\n=== Network Filesystems ===" df -t nfs -t cifs -h 2>/dev/null || echo "No network filesystems" echo -e "\n=== Temporary Filesystems ===" df -t tmpfs -h
Special Filesystems
#!/bin/bash # Show all filesystems including special ones df -a -h # Common special filesystems to ignore # - devtmpfs: Device files # - tmpfs: Temporary filesystems # - squashfs: Read-only compressed filesystems # - overlay: Overlay filesystems (containers) # Clean output without pseudo filesystems df -h -x tmpfs -x devtmpfs -x squashfs -x overlay # Docker/container filesystems df -h -t overlay # Check specific mount types check_mount_type() { local mount_point="$1" mount | grep " $mount_point " } # Example check_mount_type "/home" 5. Inode Usage
Understanding Inodes
#!/bin/bash # Show inode usage df -i df -hi # Human-readable # Check inode usage on specific filesystem df -i /home # Find filesystems with high inode usage df -i | awk 'NR>1 {gsub(/%/,"",$5); if($5>80) print $0}' # Watch inode usage watch -n 60 'df -hi | grep -v tmpfs' # Check inode limits tune2fs -l /dev/sda1 | grep -E "Inode count|Inodes per group" # Common scenarios for inode exhaustion # - Many small files (mail spools, cache directories) # - Deep directory structures # - Source code repositories # Find directories with many files find / -xdev -type d -exec sh -c ' count=$(find "$0" -maxdepth 1 -type f | wc -l) if [ $count -gt 10000 ]; then echo "$0: $count files" fi ' {} \; 2>/dev/null # Check inode usage percentage inode_usage() { local mount="$1" df -i "$mount" | awk 'NR==2 {print $5}' | tr -d '%' } # Example if [ $(inode_usage /home) -gt 90 ]; then echo "Warning: Inode usage high on /home" fi Inode Troubleshooting
#!/bin/bash # Find filesystems running out of inodes check_inodes() { local threshold="${1:-80}" df -i | awk -v thresh="$threshold" ' NR>1 { gsub(/%/,"",$5) if ($5 > thresh) { printf "WARNING: %s is at %d%% inode usage\n", $1, $5 } } ' } # Find filesystems with many files find_inode_heavy() { local mount_point="$1" echo "Top directories by file count on $mount_point:" find "$mount_point" -xdev -type d -print0 2>/dev/null | xargs -0 -I {} sh -c 'echo $(find "{}" -type f | wc -l) "{}"' | sort -rn | head -20 } # Clear inode usage by removing old files cleanup_old_files() { local dir="$1" local days="${2:-30}" echo "Removing files older than $days days in $dir" find "$dir" -type f -mtime +"$days" -delete find "$dir" -type d -empty -delete } # Monitor inode usage over time monitor_inodes() { local log_file="/var/log/inode_usage.log" while true; do echo "$(date): $(df -i /home | tail -1)" >> "$log_file" sleep 3600 # Check every hour done } 6. Script Examples
Disk Space Monitoring Script
#!/bin/bash # Comprehensive disk space monitor # Configuration THRESHOLD=80 EMAIL="[email protected]" LOG_FILE="/var/log/disk_monitor.log" EXCLUDE_TYPES="tmpfs devtmpfs squashfs overlay" # Colors for output RED='\033[0;31m' YELLOW='\033[1;33m' GREEN='\033[0;32m' NC='\033[0m' # No Color log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" echo -e "${2:-$GREEN}$1${NC}" } check_disk_usage() { local issues=0 # Build exclude pattern local exclude_args=() for type in $EXCLUDE_TYPES; do exclude_args+=(-x "$type") done df -h "${exclude_args[@]}" | tail -n +2 | while read line; do # Parse line filesystem=$(echo "$line" | awk '{print $1}') size=$(echo "$line" | awk '{print $2}') used=$(echo "$line" | awk '{print $3}') avail=$(echo "$line" | awk '{print $4}') use_pct=$(echo "$line" | awk '{print $5}' | tr -d '%') mount=$(echo "$line" | awk '{print $6}') # Check usage if [ "$use_pct" -gt "$THRESHOLD" ]; then issues=$((issues + 1)) # Critical or warning? if [ "$use_pct" -gt 90 ]; then level="CRITICAL" color="$RED" else level="WARNING" color="$YELLOW" fi message="$level: $mount ($filesystem) is ${use_pct}% full" log "$message" "$color" # Send alert if [ "$use_pct" -gt 90 ]; then echo "$message" | mail -s "Disk Alert: $mount" "$EMAIL" fi # Show top directories if [ "$use_pct" -gt 85 ]; then log "Top directories on $mount:" "$YELLOW" du -sh "$mount"/* 2>/dev/null | sort -rh | head -5 >> "$LOG_FILE" fi fi done return $issues } check_inode_usage() { local issues=0 df -i | tail -n +2 | while read line; do use_pct=$(echo "$line" | awk '{print $5}' | tr -d '%') mount=$(echo "$line" | awk '{print $6}') filesystem=$(echo "$line" | awk '{print $1}') # Skip pseudo filesystems if [[ "$filesystem" == *"tmpfs"* ]] || [[ "$filesystem" == *"devtmpfs"* ]]; then continue fi if [ "$use_pct" -gt "$THRESHOLD" ]; then issues=$((issues + 1)) log "WARNING: Inode usage on $mount is ${use_pct}% full" "$YELLOW" fi done return $issues } generate_report() { local report="/tmp/disk_report.$$" cat > "$report" << EOF Disk Space Report ================ Generated: $(date) Hostname: $(hostname) === Filesystem Usage === $(df -h -x tmpfs -x devtmpfs) === Inode Usage === $(df -hi -x tmpfs -x devtmpfs) === Largest Directories (/) === $(du -sh /* 2>/dev/null | sort -rh | head -10) === Mounted Filesystems === $(mount | column -t) EOF cat "$report" } # Main main() { log "Starting disk space check" local disk_issues=0 local inode_issues=0 check_disk_usage disk_issues=$? check_inode_usage inode_issues=$? if [ $disk_issues -gt 0 ] || [ $inode_issues -gt 0 ]; then log "Found issues: $disk_issues disk, $inode_issues inode" "$YELLOW" generate_report | mail -s "Disk Report for $(hostname)" "$EMAIL" else log "All filesystems OK" "$GREEN" fi # Archive report generate_report >> "$LOG_FILE" } # Run main main
Capacity Planning Tool
#!/bin/bash # Disk capacity planning tool CAPACITY_LOG="/var/log/capacity_history.log" TREND_DAYS=30 # Record current usage record_usage() { local timestamp=$(date +%s) df -k | tail -n +2 | while read line; do filesystem=$(echo "$line" | awk '{print $1}') used=$(echo "$line" | awk '{print $3}') mount=$(echo "$line" | awk '{print $6}') echo "$timestamp|$filesystem|$used|$mount" >> "$CAPACITY_LOG" done } # Analyze growth trend analyze_trend() { local mount="$1" local days="${2:-30}" local cutoff=$(($(date +%s) - days * 86400)) # Get historical data local data=$(grep "|$mount$" "$CAPACITY_LOG" | awk -F'|' -v cutoff="$cutoff" ' $1 >= cutoff { print $1, $3 } ' | sort -n) if [ -z "$data" ]; then echo "No historical data for $mount" return 1 fi # Calculate daily growth rate local first_usage=$(echo "$data" | head -1 | awk '{print $2}') local last_usage=$(echo "$data" | tail -1 | awk '{print $2}') local first_time=$(echo "$data" | head -1 | awk '{print $1}') local last_time=$(echo "$data" | tail -1 | awk '{print $1}') local days_diff=$(( (last_time - first_time) / 86400 )) if [ $days_diff -lt 1 ]; then days_diff=1 fi local growth_rate=$(( (last_usage - first_usage) / days_diff )) local total_size=$(df -k "$mount" | tail -1 | awk '{print $2}') local current_usage=$(df -k "$mount" | tail -1 | awk '{print $3}') echo "Analysis for $mount:" echo " Current usage: $(numfmt --to=iec $((current_usage * 1024)))" echo " Total size: $(numfmt --to=iec $((total_size * 1024)))" echo " Growth rate: $(numfmt --to=iec $((growth_rate * 1024)))/day" if [ $growth_rate -gt 0 ]; then local days_until_full=$(( (total_size - current_usage) / growth_rate )) echo " Days until full: $days_until_full" if [ $days_until_full -lt 30 ]; then echo " ⚠️ WARNING: Less than 30 days remaining!" elif [ $days_until_full -lt 90 ]; then echo " ⚠️ Less than 90 days remaining" fi fi } # Predict future usage predict_usage() { local mount="$1" local days_ahead="${2:-30}" local current=$(df -k "$mount" | tail -1 | awk '{print $3}') local total=$(df -k "$mount" | tail -1 | awk '{print $2}') # Get growth rate from trend local growth_rate=$(analyze_trend "$mount" 30 | grep "Growth rate" | awk '{print $3}') if [ -n "$growth_rate" ]; then local predicted=$((current + (growth_rate * days_ahead))) local pct=$(( predicted * 100 / total )) echo "Prediction for $days_ahead days:" echo " Current: $(numfmt --to=iec $((current * 1024)))" echo " Predicted: $(numfmt --to=iec $((predicted * 1024))) (${pct}%)" if [ $pct -gt 90 ]; then echo " ⚠️ WARNING: Predicted usage exceeds 90%" fi fi } # Main menu while true; do clear echo "=== Capacity Planning Tool ===" echo "1. Record current usage" echo "2. Show growth trends" echo "3. Predict future usage" echo "4. Generate report" echo "5. Exit" read -p "Select option: " opt case $opt in 1) record_usage echo "Usage recorded" sleep 2 ;; 2) df -h | tail -n +2 | awk '{print $6}' | while read mount; do analyze_trend "$mount" echo done read -p "Press enter to continue" ;; 3) df -h | tail -n +2 | awk '{print $6}' | while read mount; do predict_usage "$mount" 30 echo done read -p "Press enter to continue" ;; 4) { echo "Capacity Planning Report" echo "========================" echo "Date: $(date)" echo df -h echo df -h | tail -n +2 | awk '{print $6}' | while read mount; do analyze_trend "$mount" 30 echo done } > capacity_report.txt echo "Report saved to capacity_report.txt" sleep 2 ;; 5) exit 0 ;; esac done 7. Integration with Other Commands
Using with awk, grep, sort
#!/bin/bash # Find filesystems with usage > 80% df -h | awk 'NR>1 && $5+0 > 80 {print $0}' # Sort by usage percentage df -h | tail -n +2 | sort -k5 -r # Show only specific columns df -h | awk '{print $1, $5, $6}' | column -t # Create summary with awk df -h | awk ' BEGIN {print "Filesystem Summary"} NR>1 { used[$6] = $3 total[$6] = $2 pct[$6] = $5 } END { for (m in used) { printf "%-20s %-8s %-8s %s\n", m, total[m], used[m], pct[m] } }' # Find and sort by available space df -h | tail -n +2 | sort -k4 -r # Exclude certain filesystems df -h | grep -Ev '(tmpfs|devtmpfs|udev)' # Format as CSV df -h | awk ' BEGIN {print "Filesystem,Size,Used,Avail,Use%,Mounted"} NR>1 { gsub(/%/,"",$5) printf "%s,%s,%s,%s,%d,%s\n", $1, $2, $3, $4, $5, $6 }' With find and du
#!/bin/bash # Find large directories on filesystems with low space check_large_dirs() { local threshold="${1:-80}" df -h | awk -v thresh="$threshold" 'NR>1 && $5+0 > thresh {print $6}' | while read mount; do echo "Large directories on $mount:" du -sh "$mount"/* 2>/dev/null | sort -rh | head -10 echo done } # Find filesystems with specific usage patterns find_filesystems() { local usage_min="${1:-0}" local usage_max="${2:-100}" df -h | awk -v min="$usage_min" -v max="$usage_max" ' NR>1 { gsub(/%/,"",$5) if ($5 >= min && $5 <= max) { print $0 } } ' } # Monitor filesystem changes monitor_changes() { local log_file="/tmp/fs_changes.log" local snapshot1="/tmp/fs_snapshot1" local snapshot2="/tmp/fs_snapshot2" # Take first snapshot df -k > "$snapshot1" sleep 60 # Take second snapshot df -k > "$snapshot2" # Compare diff "$snapshot1" "$snapshot2" | grep -E '^[<>]' | while read line; do echo "$(date): $line" >> "$log_file" done } 8. Performance Monitoring
Real-time Monitoring
#!/bin/bash # Watch disk usage in real-time watch -n 5 'df -h | grep -v tmpfs' # Monitor specific mount point with alerts monitor_mount() { local mount="$1" local interval="${2:-10}" local threshold="${3:-90}" while true; do usage=$(df -h "$mount" | tail -1 | awk '{print $5}' | tr -d '%') if [ "$usage" -gt "$threshold" ]; then echo "$(date): WARNING - $mount is ${usage}% full" fi sleep "$interval" done } # Graph disk usage over time graph_usage() { local mount="$1" local points="${2:-60}" local interval="${3:-10}" for i in $(seq 1 $points); do usage=$(df -h "$mount" | tail -1 | awk '{print $5}' | tr -d '%') bars=$((usage / 2)) printf "%3d%% [%s%s]\n" $usage \ "$(printf '█%.0s' $(seq 1 $bars))" \ "$(printf '░%.0s' $(seq 1 $((50 - bars))))" sleep "$interval" done } # Usage # monitor_mount / 30 85 # graph_usage / 100 5 Historical Tracking
#!/bin/bash # Log disk usage to database (simple flat file) LOG_DIR="/var/log/disk_usage" mkdir -p "$LOG_DIR" log_usage() { local timestamp=$(date +%s) local date=$(date +%Y%m%d) df -k | tail -n +2 | while read line; do filesystem=$(echo "$line" | awk '{print $1}') used=$(echo "$line" | awk '{print $3}') mount=$(echo "$line" | awk '{print $6}' | tr '/' '_') echo "$timestamp $used" >> "$LOG_DIR/${date}_${mount}.log" done } # Analyze historical data analyze_history() { local mount_point="$1" local days="${2:-7}" local mount_safe=$(echo "$mount_point" | tr '/' '_') echo "Analysis for $mount_point over last $days days:" echo "Date Used(MB) Change" echo "---------- -------- ------" local prev_used=0 for log in $(ls -t "$LOG_DIR"/*_"$mount_safe".log | head -"$days"); do date=$(basename "$log" | cut -d_ -f1) used=$(tail -1 "$log" | awk '{print $2}') used_mb=$((used / 1024)) if [ $prev_used -ne 0 ]; then change=$((used_mb - prev_used)) printf "%s %8d %+6d\n" "$date" "$used_mb" "$change" else printf "%s %8d %6s\n" "$date" "$used_mb" "-" fi prev_used=$used_mb done } # Setup cron job # */5 * * * * /usr/local/bin/disk_logger.sh 9. Formatting and Output Control
Custom Output Formats
#!/bin/bash # Pretty print with colors color_df() { df -h | awk ' BEGIN { red = "\033[31m" yellow = "\033[33m" green = "\033[32m" blue = "\033[34m" reset = "\033[0m" } NR==1 { print blue $0 reset } NR>1 { gsub(/%/,"",$5) if ($5 > 90) color = red else if ($5 > 75) color = yellow else color = green $5 = $5"%" printf "%s%s%s\n", color, $0, reset }' } # CSV output df_csv() { df -h | awk ' BEGIN {print "filesystem,size,used,avail,use_pct,mount"} NR>1 { gsub(/%/,"",$5) printf "%s,%s,%s,%s,%d,%s\n", $1, $2, $3, $4, $5, $6 }' } # JSON output df_json() { echo "{" echo ' "timestamp": "'$(date -Iseconds)'",' echo ' "filesystems": [' df -h | tail -n +2 | awk ' BEGIN {sep=""} { gsub(/%/,"",$5) printf "%s {\n", sep printf " \"filesystem\": \"%s\",\n", $1 printf " \"size\": \"%s\",\n", $2 printf " \"used\": \"%s\",\n", $3 printf " \"available\": \"%s\",\n", $4 printf " \"use_percent\": %d,\n", $5 printf " \"mount\": \"%s\"\n", $6 printf " }" sep=",\n" }' echo "" echo ' ]' echo "}" } # HTML report df_html() { cat << EOF <html> <head> <title>Disk Usage Report</title> <style> body { font-family: Arial, sans-serif; } table { border-collapse: collapse; width: 100%; } th { background: #4CAF50; color: white; padding: 8px; } td { border: 1px solid #ddd; padding: 8px; } tr:nth-child(even) { background: #f2f2f2; } .critical { background: #ff4444; color: white; } .warning { background: #ffaa00; } </style> </head> <body> <h2>Disk Usage Report - $(date)</h2> <table> <tr> <th>Filesystem</th> <th>Size</th> <th>Used</th> <th>Avail</th> <th>Use%</th> <th>Mounted on</th> </tr> EOF df -h | tail -n +2 | awk ' { gsub(/%/,"",$5) class = "" if ($5 > 90) class = "critical" else if ($5 > 75) class = "warning" printf " <tr class=\"%s\">\n", class printf " <td>%s</td>\n", $1 printf " <td>%s</td>\n", $2 printf " <td>%s</td>\n", $3 printf " <td>%s</td>\n", $4 printf " <td>%d%%</td>\n", $5 printf " <td>%s</td>\n", $6 printf " </tr>\n" }' cat << EOF </table> </body> </html> EOF } # Usage # color_df # df_csv > report.csv # df_json > report.json # df_html > report.html 10. Alerting and Notifications
Alert Scripts
#!/bin/bash # Multi-channel alert system CONFIG_FILE="/etc/disk_alert.conf" ALERT_LOG="/var/log/disk_alerts.log" # Default thresholds WARN_THRESHOLD=80 CRIT_THRESHOLD=90 # Load configuration if [ -f "$CONFIG_FILE" ]; then source "$CONFIG_FILE" fi # Alert channels send_email() { local subject="$1" local message="$2" echo "$message" | mail -s "$subject" "${ALERT_EMAIL:[email protected]}" } send_slack() { local message="$1" local webhook="${SLACK_WEBHOOK:-}" if [ -n "$webhook" ]; then curl -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"$message\"}" \ "$webhook" 2>/dev/null fi } log_alert() { local level="$1" local message="$2" echo "$(date -Iseconds) [$level] $message" >> "$ALERT_LOG" } # Check and alert check_and_alert() { local issues=0 df -h | tail -n +2 | while read line; do use_pct=$(echo "$line" | awk '{print $5}' | tr -d '%') mount=$(echo "$line" | awk '{print $6}') filesystem=$(echo "$line" | awk '{print $1}') if [ "$use_pct" -gt "$CRIT_THRESHOLD" ]; then issues=$((issues + 1)) message="CRITICAL: $mount ($filesystem) is ${use_pct}% full" log_alert "CRITICAL" "$message" send_email "CRITICAL Disk Alert" "$message" send_slack ":fire: $message" elif [ "$use_pct" -gt "$WARN_THRESHOLD" ]; then issues=$((issues + 1)) message="WARNING: $mount ($filesystem) is ${use_pct}% full" log_alert "WARNING" "$message" # Only email for warnings, maybe not Slack send_email "Disk Warning" "$message" fi done return $issues } # Escalation if issues persist escalate_alert() { local mount="$1" local count_file="/tmp/alert_count_$(echo "$mount" | tr '/' '_')" local max_count=3 if [ -f "$count_file" ]; then count=$(cat "$count_file") else count=0 fi count=$((count + 1)) echo "$count" > "$count_file" if [ "$count" -ge "$max_count" ]; then # Escalate - page on-call send_email "ESCALATED: Disk alert for $mount" "Issue persisting" # Could also send SMS, page, etc. rm -f "$count_file" # Reset after escalation fi } # Main loop while true; do check_and_alert sleep 300 # Check every 5 minutes done 11. Troubleshooting
Common Issues and Solutions
#!/bin/bash # Issue: "df: cannot read table of mounted filesystems" # Solution: Check /etc/mtab or /proc/mounts if [ ! -f /etc/mtab ]; then echo "mtab missing, using /proc/mounts" alias df='df -P' fi # Issue: Stale NFS mount causing hang # Solution: Use timeout and exclude stale mounts timeout_df() { local timeout="${1:-10}" timeout "$timeout" df -h 2>/dev/null || echo "df command timed out" } # Find stale NFS mounts find_stale_nfs() { mount -t nfs | awk '{print $3}' | while read mount; do timeout 5 ls "$mount" >/dev/null 2>&1 || echo "Stale NFS: $mount" done } # Issue: Permission denied for some mounts # Solution: Use sudo for system mounts sudo_df() { sudo df -h "$@" } # Issue: Inconsistent sizes due to mounted filesystems # Solution: Use --direct to avoid stat overhead (GNU) df --direct -h # Issue: Binary mount point names # Solution: Use -P for POSIX format df -P # Debug df operations debug_df() { strace -e trace=file df -h 2>&1 | grep -E 'open|stat' } Diagnostic Tools
#!/bin/bash # Comprehensive disk diagnostic diagnose_disk() { local mount="${1:-/}" echo "=== Disk Diagnostics for $mount ===" echo echo "1. Basic filesystem info:" df -h "$mount" echo echo "2. Filesystem type:" df -T "$mount" echo echo "3. Inode usage:" df -i "$mount" echo echo "4. Mount options:" mount | grep " $mount " echo echo "5. Filesystem features:" device=$(df "$mount" | tail -1 | awk '{print $1}') if [ -b "$device" ]; then tune2fs -l "$device" 2>/dev/null | head -10 || echo "Not an ext filesystem" fi echo echo "6. Disk I/O stats:" iostat -x 1 2 2>/dev/null | tail -20 || echo "iostat not available" echo echo "7. Top directories by size:" du -sh "$mount"/* 2>/dev/null | sort -rh | head -10 echo echo "8. Open files on this filesystem:" lsof "$mount" 2>/dev/null | head -10 || echo "No open files or lsof not available" } # Check for disk errors check_disk_errors() { dmesg | grep -i "error\|i/o error\|disk full" | tail -20 } # Validate filesystem validate_fs() { local mount="$1" local device=$(df "$mount" | tail -1 | awk '{print $1}') # Unmount first (if possible) echo "This would check $device - requires unmount" # sudo fsck -f "$device" } 12. Best Practices and Tips
Shell Configuration
# ~/.bashrc additions # Aliases for common df operations alias df='df -h' # Human-readable by default alias dfc='df -h --total' # With total alias dfl='df -h -l' # Local only alias dfi='df -hi' # Inodes alias dfext='df -h -t ext4 -t xfs' # Only ext4 and xfs alias dfhome='df -h /home' # Home directory alias dfroot='df -h /' # Root filesystem # Function to show usage with colors dfcolor() { df -h | awk ' BEGIN { red="\033[31m" yellow="\033[33m" green="\033[32m" blue="\033[34m" reset="\033[0m" } NR==1 {print blue $0 reset; next} { gsub(/%/,"",$5) color = ($5 > 90) ? red : ($5 > 75) ? yellow : green printf "%s%s%s\n", color, $0, reset }' } # Function to show top usage dftop() { local n="${1:-5}" df -h | tail -n +2 | sort -k5 -rn | head -"$n" } # Function to monitor specific mount dfwatch() { local mount="${1:-/}" local interval="${2:-5}" watch -n "$interval" "df -h '$mount'" } # Complete with mount points _df_complete() { COMPREPLY=($(compgen -W "$(mount | awk '{print $3}')" -- "${COMP_WORDS[COMP_CWORD]}")) } complete -F _df_complete dfwatch dftop System Administration Tips
#!/bin/bash # 1. Regular monitoring setup (cron) cat > /etc/cron.d/disk_monitor << 'EOF' */15 * * * * root /usr/local/bin/check_disk.sh >> /var/log/disk_check.log 2>&1 0 0 * * * root /usr/local/bin/disk_report.sh | mail -s "Daily Disk Report" [email protected] EOF # 2. Alert thresholds configuration cat > /etc/disk_alert.conf << 'EOF' WARN_THRESHOLD=80 CRIT_THRESHOLD=90 [email protected] SLACK_WEBHOOK=https://hooks.slack.com/services/xxx/yyy/zzz EXCLUDE_FS="tmpfs devtmpfs squashfs" EOF # 3. Automated cleanup when low on space auto_cleanup() { local mount="$1" local threshold="${2:-90}" usage=$(df -h "$mount" | tail -1 | awk '{print $5}' | tr -d '%') if [ "$usage" -gt "$threshold" ]; then echo "Disk usage critical on $mount, cleaning up..." # Clean package manager cache if [ -d /var/cache/apt ]; then apt-get clean fi # Remove old logs find /var/log -name "*.log" -mtime +30 -delete find /var/log -name "*.gz" -mtime +30 -delete # Remove old kernels (Ubuntu) if command -v apt-get >/dev/null; then apt-get autoremove --purge -y fi # Clear journal logs older than 7 days journalctl --vacuum-time=7d 2>/dev/null fi } # 4. Create alerts for trending trend_alert() { local mount="$1" local log_file="/tmp/${mount}_trend.log" # Record current usage usage=$(df -h "$mount" | tail -1 | awk '{print $5}' | tr -d '%') echo "$(date +%s) $usage" >> "$log_file" # Keep last 30 days tail -n 30 "$log_file" > "${log_file}.tmp" mv "${log_file}.tmp" "$log_file" # Calculate trend if [ $(wc -l < "$log_file") -ge 7 ]; then first=$(head -1 "$log_file" | awk '{print $2}') last=$(tail -1 "$log_file" | awk '{print $2}') if [ "$last" -gt "$first" ]; then echo "Warning: $mount usage trending up ($first% -> $last%)" fi fi } # 5. Emergency actions emergency_actions() { local mount="$1" # Find and kill processes using too much space lsof "$mount" 2>/dev/null | awk '{print $2}' | sort -u | while read pid; do if [ -d "/proc/$pid" ]; then size=$(ls -l "/proc/$pid/fd" 2>/dev/null | grep -c "deleted") if [ "$size" -gt 100 ]; then echo "Process $pid has deleted files consuming space" # kill -9 "$pid" # Uncomment with caution fi fi done }
Conclusion
The df command is essential for system administration and disk space monitoring:
Key Takeaways
- Basic Usage:
dfshows filesystem disk usage - Human-readable:
-hfor understandable sizes - Filesystem Types:
-Tshows type,-tfilters by type - Inodes:
-ishows inode usage - Local Only:
-lexcludes network filesystems - Total:
--totalshows sum of all - Custom Output: Can be formatted with awk, sed
- Integration: Works great with other commands
- Monitoring: Essential for automated monitoring
- Troubleshooting: Helps identify disk issues
Best Practices Summary
- Always use
-hfor human-readable output - Monitor regularly with cron jobs
- Set up alerts for high usage
- Check both space and inodes
- Exclude pseudo filesystems for clean reports
- Track trends for capacity planning
- Integrate with monitoring systems
- Document thresholds and actions
- Test cleanup procedures before emergencies
- Keep historical data for analysis
The df command, while simple, is crucial for maintaining system health and preventing outages due to full disks. Combined with other tools and proper monitoring, it forms the foundation of disk space management in Unix/Linux systems.
Complete Bash Exercises with Solutions
Practice Bash scripting with solved exercises to improve your command-line and scripting skills.
Link: https://macronepal.com/complete-bash-exercises-with-solutions/
Complete Guide to Bash Crontab Command
Learn how to schedule and automate tasks efficiently using the Bash crontab command.
Link: https://macronepal.com/complete-guide-to-bash-crontab-command-schedule-tasks/
Complete Guide to Bash Arrays
Understand how to create, manage, and use arrays in Bash scripting.
Link: https://macronepal.com/complete-guide-to-bash-arrays/
Bash Quiz: Test Your Knowledge
Test your Bash scripting knowledge with quizzes and practical questions.
Link: https://macronepal.com/bash-quiz-test-your-knowledge/
Complete Guide to Bash Functions
Learn how to write reusable Bash functions for cleaner and efficient scripts.
Link: https://macronepal.com/complete-guide-to-bash-functions/
Complete Guide to Bash Loops
Master loops in Bash for repetitive tasks and automation.
Link: https://macronepal.com/complete-guide-to-bash-loops/
Complete Guide to Bash If-Else Statements
Learn decision-making in Bash using conditional statements.
Link: https://macronepal.com/complete-guide-to-bash-ifelse-statements/
Complete Guide to Bash Operators
Explore arithmetic, logical, and comparison operators in Bash.
Link: https://macronepal.com/complete-guide-to-bash-operators/
Complete Guide to Bash Data Types
Understand variables and different data types used in Bash scripting.
Link: https://macronepal.com/complete-guide-to-bash-data-types/
Complete Guide to Bash Variables
Learn how to declare, assign, and use variables in Bash scripts.
Link: https://macronepal.com/complete-guide-to-bash-variables/
Complete Guide to Bash Scripting
A complete introduction to writing Bash scripts for automation.
Link: https://macronepal.com/complete-guide-to-bash-scripting/
Complete Guide to Basic Bash Syntax
Learn the fundamental syntax needed to write Bash commands and scripts.
Link: https://macronepal.com/complete-guide-to-basic-bash-syntax/
Complete Guide to Bash Chgrp Command
Learn how to change group ownership of files and directories.
Link: https://macronepal.com/complete-guide-to-bash-chgrp-command-change-group-ownership-2/
Complete Guide to Bash Chgrp Command (Alternate)
Another detailed explanation of Bash group ownership management.
Link: https://macronepal.com/complete-guide-to-bash-chgrp-command-change-group-ownership/
Complete Guide to Bash File Permissions and Ownership
Understand Linux file permissions and ownership management.
Link: https://macronepal.com/complete-guide-to-bash-file-permissions-and-ownership/
Complete Guide to Bash Chmod Command
Learn how to modify file permissions using chmod.
Link: https://macronepal.com/complete-guide-to-bash-chmod-command-change-file-permissions/
Complete Guide to Bash Chown Command
Change file ownership using the Bash chown command.
Link: https://macronepal.com/complete-guide-to-bash-chown-command-change-file-ownership/
Complete Guide to Bash SCP Command
Securely transfer files between systems using SCP.
Link: https://macronepal.com/complete-guide-to-bash-scp-command-secure-copy/
Complete Guide to Bash SSH Command
Learn secure remote access and server management using SSH.
Link: https://macronepal.com/complete-guide-to-bash-ssh-command/
Bash Wget Command Complete Guide
Download files from the internet using the wget command.
Link: https://macronepal.com/bash-wget-command-complete-guide-to-non-interactive-network-downloader/
