我正在尝试执行特定的 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
将其用于创建或写入磁盘映像的典型用法:dd
pv
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