Bash 读取 rsync 进度并在太慢时放弃文件的脚本

Bash script that reads rsync progress and bails on the file if too slow

我对 bash 脚本编写的经验太少了,这很可笑。

我花了 3 天时间将文件从我 NAS 上发生故障的硬盘驱动器(LVM 中的 3 个硬盘驱动器中的 1 个)传输到新硬盘驱动器。大多数(按百分比计算)文件传输正常,但许多(数千)文件受到影响,而不是因 i/o 错误而失败,它们将速度降低到令人痛苦的速度。

我使用的是一个简单的 cp 命令,但后来我切换到 rsync 并使用 --progress 选项至少能够确定发生这种情况的时间。

目前,我正在手动观看屏幕(当我们谈论 DAYS 时很糟糕),挂断时 ^C,然后复制文件名并将其粘贴到排除文件中并重新启动 rsync。

需要来自动化!

我对 bash 脚本一无所知,但我想我可能 "watch" 标准输出,解析速率信息并使用这样的逻辑:

if rate is less than 5Mbps for 3 consecutive seconds, bail and restart

这是我正在使用的 rsync 命令: rsync -aP --ignore-existing --exclude-from=EXCLUDE /mnt/olddisk/ /mnt/newdisk/

这是进度的示例输出:

path/to/file.ext
    3434,343,343 54%  144.61MB/s   0:00:05 (xfr#1, ir-chk=1024/1405)

因此解析第 2 行的第 3 列并确保它不会太慢,如果太慢则终止命令,将文件名附加到 EXCLUDE 并再试一次。

有人可以帮我吗?

这是一种糟糕的方法,我不希望它能有效地解决您的问题。但是,以下是对您问题的字面回答。

#!/usr/bin/env bash
[[  ]] || {
  echo "Usage: rsync -P --exclude=exclude-file ... | [=10=] exclude-file" >&2
  exit 1
}

is_too_slow() {
  local rate=
  case $rate in
    *kB/s)          return 0 ;;
    [0-4][.]*MB/s)  return 0 ;;
    *)              return 1 ;;
  esac
}

exclude_file=
last_slow_time=0

filename=
too_slow_count=0
while IFS=$'\n' read -r -d $'\r' -a pieces; do
  for piece in "${pieces[@]}"; do
    case $piece in
      "sending incremental file list") continue ;;
      [[:space:]]*)
        read -r size pct rate time <<<"$piece"
        if is_too_slow "$rate"; then
          if (( last_slow_time == SECONDS )); then
            continue # ignore multiple slow results in less than a second
          fi
          last_slow_time=$SECONDS
          if (( ++too_slow_count > 3 )); then
            echo "$filename" >>"$exclude_file"
            exit 1
          fi
        else
          too_slow_count=0
        fi
        ;;
      *) filename=$piece; too_slow_count=0 ;;
    esac
  done
done