为 Zenity 进度格式化管道 rsync 输出

Formatting piped rsync output for Zenity progress

我正在执行 rsync 过程以从 SD 卡复制文件,我想在每个文件的 rsync 过程中显示 Zenity 中每个文件的进度。我尝试了 Zenity and rsync,这对我来说似乎很完美。它应该发送当前文件并将 % 复制到 Zenity,但我无法获取它,输出不是实时的并且不会移动进度条。而且我不明白为什么它不起作用。

我至少要做的是将文件副本的百分比发送到 Zenity 以驱动进度条。但这需要是一个没有尾随 % 的数字来驱动进度条。

这不会输出任何内容,但如果我删除 sed 和 Zenity 步骤,我会得到:0%、1%、2% 等。但是 Zenity 需要非百分比值。

sudo rsync -av  --info=progress2  "$f"/*.MP4 $copydest | \
strace -e trace=read grep "[0-9]*%" 2>&1 > /dev/null | grep -o "[[:digit:]]*%" | sed 's/[^0-9]//g' | \
zenity  --width=400 --height=20 --progress  --percentage=0  --text="Copying...." --auto-close  --auto-kill \
 --title="Copying $tc from  $cardname"

理想情况下,我也希望显示当前文件名,但我卡住了。例如,

Filename.MP4
.......... (progress)

在 grep 或 sed 或 awk 中必须有一个方法,我可以获取 MP4 文件名和作为数字复制的百分比,但它超出了我的范围。

这是 rsync 将在 3 个文件上输出的内容,其中 % 和剩余时间递增等

25_nn67_P1680210.MP4
  1,024,202,031 100%  163.00MB/s    0:00:05 (xfr#1, to-chk=2/3)
25_nn67_P1680211.MP4
    146,801,421 100%   49.12MB/s    0:00:02 (xfr#2, to-chk=1/3)
25_nn67_P1680212.MP4

一个相对简单的选项是捕获当前文件,当前文件的百分比:

rsync -av --info=progress2 ...  |
   tr '\r' '\n' |
   awk '/^ / { print int(+) ; next } [=10=] { print "# " [=10=] }' |
   zenity --progress ...

显示整体完成率更具挑战性。这将需要 运行ning rsync 两次 - 一次在 dry-运行 模式下,计算要移动的文件数,然后使用文件数计算进度百分比。

不用说,这会稍微增加实际副本的延迟。

下面的代码假定所有文件都需要相同的时间来复制。它需要一些工作来执行文件计数的实际估计,因为日志包含很少的其他消息(总字节数等)。

(
echo "5" ; echo "Calculate job Size"
file_count=$(rsync --dry-run -av  feature_files/ fff/ | wc -l)
echo "F=$file_count"

rsync -av --info=progress2 feature_files/ fff/ |
   tr '\r' '\n' |
   awk -v "total=$file_count" '
/^ / { print 100*(count+/100)/total ; next }
[=10=] { print "# " [=10=] ; count++ ; print 100*count/total }
'
) | zenity --progress ...

好的,我修复了它,非常感谢 dash-o 提供的格式化帮助 - 辛苦了。 问题出在管道缓冲上,因此 Zenity 在缓冲区已满之前无法获取任何数据——这可能从来没有出现过我 运行 的测试文件集。 您需要将管道中所有步骤的缓冲区(在 zenity 之前)设置为 0:

sudo  rsync -av  --info=progress2  "$f"/*.MP4 $copydest | \
stdbuf -i0 -o0 -e0 tr '\r' '\n' | stdbuf -i0 -o0 -e0  awk -W interactive -f /path/to/rsync.awk |  zenity --progress  --width=400   --text="Copying...." --auto-close --title="Copying $cardname"  

然后在 rsync.awk 中(它可能不需要额外的文件就可以工作)添加 fflush() 确保它刷新。

#!/bin/sh
/^ / { print int(+) ; fflush() ;  next } [=11=] { print "# " [=11=]  }

所以现在,执行 rsync(通过先前的 Zenity 对话)导致进度 window,其中包含当前文件名和移动进度条,同时 Rsync 复制每个文件 - 注意:不是整体进度,而是对于每个复制的文件。

现在我的脚本在插入包含 MP4 文件的 SD 卡时触发,并使用 rsync 进行复制,并显示工作进度条。