dd 在管道输出时显示“原始”进度

dd 在管道输出时显示“原始”进度

我正在尝试执行特定的 dd 操作,并将传输的“原始”数据附加到日志文件中,该日志文件将由其他东西轮询,以在另一个接口(即不是终端)上提供传输的实时视图。

dd操作是:

dd if=/some/lvm bs=512K | gzip -c > /tmp/whatever

我能看到的最简单的方法是将该命令输出到文件并同时终止 -SIGUSR1 pid 并查看输出,尽管我找不到将进程的 pid 存储在变量中并在终止命令中使用它的方法。

我见过这个两班轮:

dd if=/some/lvm of=/some/fat/image/which/I/cant/use bs=512K& pid=$!; \
sleep 1; while [[ -d /proc/$pid ]]; do kill -USR1 $pid && sleep 1; done

虽然我不太明白它如何将 pid 作为变量,所以我无法修改它以使用我的管道输出。

我很高兴看到 dd 的替代方案,尽管大多数方案只是给出了更多的复杂性,例如 dcfldd ,它更新了同一行,但我认为是类似诅咒的方法。这使得每秒提取该输出的快照并提取我需要的数据变得困难。如果有一种简单的方法我可以处理这个问题,或者如果我可以获得“原始”输出,甚至可以通过管道传输到光伏。

请赐教。 ;-)

问候

编辑:所以我找到了一个“解决方案”,它仍然不漂亮,但是

我可以使用 pgrep 查找进程 ID,因此当 dd 命令运行并输出到文件时,我会watch -n1 'sudo kill -USR1 $(pgrep ^dd)'每秒运行输出传输进度,轮询器可以解释该进度。

这仍然不是一个优雅的解决方案,感觉就像一个困境。如果有更好的方法我仍然愿意接受建议。 :-)

答案1

最好的答案是pv,它可以让您看到可以通过管道传输的任何进程的进度。

dd if=/some/lvm bs=512K | pv | gzip -c > /tmp/whatever

您甚至可以通过以下方式dd将其用于创建或写入磁盘映像的典型用法:ddpv

dd if=/dev/cdrom | pv | dd of=/path/to/some.iso

答案2

这是一个可以实现目标的脚本:

(
        dd if=/some/lvm bs=512K &
        pid_dd=$!

        while :; do
                sleep 1
                kill -USR1 $pid_dd
        done &
        pid_monitor=$!

        wait $pid_dd
        kill $pid_monitor
) |
        gzip -c > /tmp/whatever

答案3

为了那些可能仍然偶然发现这一点的人的兴趣:

如果你想 grep 或处理 dd 的进度,你可以用一些括号括起来。由于kill触发的输出会发送到stderr,因此您可以重定向2>&1以使其可greppable:

# ( DP=$(
 dd if=/proc/kcore of=/dev/null bs=1M count=50000 &
 echo $!);  while kill -USR1 $DP 2>/dev/null; do sleep 1; done ) 2>&1 |grep copied
0 bytes copied, 1.73e-05 s, 0.0 kB/s
21043871744 bytes (21 GB, 20 GiB) copied, 1.01827 s, 20.7 GB/s
42920312832 bytes (43 GB, 40 GiB) copied, 2.02764 s, 21.2 GB/s
52428800000 bytes (52 GB, 49 GiB) copied, 2.49048 s, 21.1 GB/s
#

添加拉链使它变得有趣 - 我们将需要更多括号!因为我们需要绕道 >&3 来为 gzip 保留 >&1:

    # ZIPFILE=/path/to/zipfile..
    # ( DP=$(
((dd if=/proc/kcore bs=1M count=500 & echo $! >&3 ) | gzip > $ZIPFILE & ) 3>&1|head -1); 
    sleep 1 # wait for dd startup; 
    while kill -USR1 $DP 2>/dev/null ; do sleep 1; done) 2>&1|grep copied
    241172480 bytes (241 MB, 230 MiB) copied, 1.00001 s, 241 MB/s
    486539264 bytes (487 MB, 464 MiB) copied, 2.00568 s, 243 MB/s
    524288000 bytes (524 MB, 500 MiB) copied, 2.16047 s, 243 MB/s

修改 dd 以适合您的目的。
附言。这属于包装脚本,然后将 |grep 或其他内容移到脚本之外。或者反其道而行之,在一行上也能正常工作:-)

答案4

如果您无法使用pv,那么您就走在正确的道路上kill -USR1。鉴于您最初的命令dd if=/some/lvm bs=512K | gzip -c > /tmp/whatever,我会在一对脚本的上下文中执行类似的操作:

dd if=/some/lvm bs=512K | gzip -c > /tmp/whatever &
PID=$! # $! is set to the PID of the last backgrounded process
echo $PID > /var/run/dd_pid.txt  # So that other scripts can read it
fg
rm /var/run/dd_pid.txt

同时,在您的其他脚本中:

PID=$(cat /var/run/dd_pid.txt)
if [[ 0 -ne $? ]]; then
    echo 'PID file not found'
    exit 1
fi
while kill -0 $PID; do
    sleep 1
    kill -USR1 $PID
done

相关内容