请求编写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
- Save the script: Copy the code above into a file named
rsync_monitor.sh. - Make it executable: Run
chmod +x rsync_monitor.shin your terminal. - Configure the top section: Double-check that
SOURCE,DEST, andEXCLUDE_FILEpoint to your actual paths. - Run it: Execute
./rsync_monitor.shin the same directory where yourEXCLUDEfile is located.
Step 3: Key Details Explained
- Temporary Log File: We use
mktempto 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
bcfor floating-point math—make sure it's installed on your system (runsudo apt install bcif you're on Debian/Ubuntu). - Filename Extraction: The
sedcommand grabs everything before the speed value in the rsync output line, thenxargstrims 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
SOURCEends 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_FILEand both the source/destination directories. - Testing: If you want to test the script first, you can lower the
LOW_THRESHOLD_MBPSandLOW_DURATIONvalues (e.g., 1Mbps and 1 second) to trigger the action quickly. - Slow Files: The excluded files are added to your
EXCLUDElist permanently, so you can review them later to decide if you want to attempt transferring them manually (maybe with a different tool likeddfor problematic sectors).
内容的提问来源于stack exchange,提问作者bcsteeve
相关产品推荐
相关产品推荐

