You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求编写Bash脚本监控rsync传输,低速时自动终止并排除文件

Got it, let's build a Bash script that automates exactly what you need—monitoring rsync's transfer speed, killing the process when it stays below 5Mbps for 3 seconds, adding the problematic file to your EXCLUDE list, and restarting rsync. Since you're new to Bash, I'll break down every part so you understand how it works.

Step 1: Complete Automation Script

Save this as rsync_monitor.sh (make sure to adjust the paths at the top to match your setup):

#!/bin/bash

# -------------------------- CONFIGURATION --------------------------
EXCLUDE_FILE="EXCLUDE"       # Path to your exclude list file
SOURCE="/mnt/olddisk/"       # Source directory (trailing slash matters!)
DEST="/mnt/newdisk/"         # Destination directory
LOW_THRESHOLD_MBPS=5         # Speed threshold in Mbps
LOW_DURATION=3               # How long to wait before triggering action (seconds)
# -------------------------------------------------------------------

# Ensure exclude file exists (create if missing)
touch "$EXCLUDE_FILE"

# Function to start rsync and monitor its output
run_rsync_with_monitor() {
    # Create a temporary log file to capture rsync output
    local temp_log=$(mktemp)
    echo "Created temporary log file: $temp_log"

    # Start rsync in the background, redirect output to temp log
    rsync -aP --ignore-existing --exclude-from="$EXCLUDE_FILE" "$SOURCE" "$DEST" 2>&1 > "$temp_log" &
    local rsync_pid=$!
    echo "Started rsync process with PID: $rsync_pid"

    # Initialize timer variables
    local low_speed_start_time=""

    # Monitor the log file in real-time
    tail -f "$temp_log" | while read -r line; do
        # Print rsync output to terminal so you can see progress
        echo "$line"

        # Check if this line is a transfer progress line (contains "xfr#")
        if [[ "$line" =~ xfr# ]]; then
            # Extract speed info (e.g., "144.61MB/s" or "500KB/s")
            if [[ "$line" =~ ([0-9]+\.?[0-9]*)([KM]B/s) ]]; then
                local rate_val="${BASH_REMATCH[1]}"
                local rate_unit="${BASH_REMATCH[2]}"

                # Convert speed to Mbps (1 MB/s = 8 Mbps; 1 KB/s = 8/1024 Mbps)
                local rate_mbps
                if [[ "$rate_unit" == "MB/s" ]]; then
                    rate_mbps=$(echo "$rate_val * 8" | bc -l)
                else # KB/s
                    rate_mbps=$(echo "$rate_val * 8 / 1024" | bc -l)
                fi

                # Compare current speed to threshold
                if (( $(echo "$rate_mbps < $LOW_THRESHOLD_MBPS" | bc -l) )); then
                    local current_time=$(date +%s)
                    # If this is the first low speed detection, start the timer
                    if [[ -z "$low_speed_start_time" ]]; then
                        low_speed_start_time="$current_time"
                        echo "⚠️  Low speed detected: $rate_mbps Mbps. Starting $LOW_DURATION-second timer..."
                    else
                        # Calculate how long speed has been low
                        local duration=$((current_time - low_speed_start_time))
                        if [[ "$duration" -ge "$LOW_DURATION" ]]; then
                            echo "🚨 Low speed persisted for $duration seconds. Taking action..."

                            # Extract the problematic filename (everything before the speed value)
                            local filename=$(echo "$line" | sed -E "s/^\s*(.*)\s+$rate_val$rate_unit.*$/\1/" | xargs)
                            echo "Identified slow file: '$filename'"

                            # Add filename to exclude list
                            echo "$filename" >> "$EXCLUDE_FILE"
                            echo "Added '$filename' to $EXCLUDE_FILE"

                            # Kill the rsync process
                            kill "$rsync_pid"
                            echo "Terminated rsync process (PID: $rsync_pid)"

                            # Clean up and exit the monitoring loop
                            low_speed_start_time=""
                            break
                        fi
                    fi
                else
                    # Speed is normal; reset the timer
                    low_speed_start_time=""
                fi
            fi
        fi
    done

    # Wait for rsync to finish (whether killed or completed)
    wait "$rsync_pid" 2>/dev/null

    # Clean up temporary log file
    rm "$temp_log"
    echo "Removed temporary log file"

    # Return rsync's exit code (0 = success, non-zero = killed/error)
    return $?
}

# Main loop: keep restarting rsync until it completes successfully
while true; do
    run_rsync_with_monitor
    local exit_code=$?

    if [[ "$exit_code" -eq 0 ]]; then
        echo "✅ Rsync completed successfully! All files transferred (excluding slow ones)."
        break
    else
        echo "🔄 Rsync was terminated or encountered an error. Restarting in 2 seconds..."
        sleep 2
    fi
done
Step 2: How to Use the Script
  1. Save the script: Copy the code above into a file named rsync_monitor.sh.
  2. Make it executable: Run chmod +x rsync_monitor.sh in your terminal.
  3. Configure the top section: Double-check that SOURCE, DEST, and EXCLUDE_FILE point to your actual paths.
  4. Run it: Execute ./rsync_monitor.sh in the same directory where your EXCLUDE file is located.
Step 3: Key Details Explained
  • Temporary Log File: We use mktemp to create a temporary log so we can monitor rsync's output in real-time without missing anything.
  • Speed Conversion: The script converts rsync's output (MB/s or KB/s) to Mbps to match your threshold (5Mbps). We use bc for floating-point math—make sure it's installed on your system (run sudo apt install bc if you're on Debian/Ubuntu).
  • Filename Extraction: The sed command grabs everything before the speed value in the rsync output line, then xargs trims any extra spaces (handles filenames with leading/trailing spaces, though filenames with spaces in the middle still work here).
  • Loop Logic: The main loop restarts rsync automatically after it's killed, until rsync completes with exit code 0 (meaning all remaining files transferred successfully).
Step 4: Important Notes
  • Trailing Slashes: Make sure SOURCE ends with a trailing slash (/mnt/olddisk/ instead of /mnt/olddisk)—this tells rsync to copy the contents of the directory, not the directory itself.
  • File Permissions: Ensure you have write access to the EXCLUDE_FILE and both the source/destination directories.
  • Testing: If you want to test the script first, you can lower the LOW_THRESHOLD_MBPS and LOW_DURATION values (e.g., 1Mbps and 1 second) to trigger the action quickly.
  • Slow Files: The excluded files are added to your EXCLUDE list permanently, so you can review them later to decide if you want to attempt transferring them manually (maybe with a different tool like dd for problematic sectors).

内容的提问来源于stack exchange,提问作者bcsteeve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:55:37