我有一个脚本解压缩.gz
文件并将其复制到块设备中。我使用dd
来获取有关进度的信息(我不能使用其他实用程序,例如pv
来执行此操作)。这是脚本的一部分:
#!/bin/sh
set -e
trap 'true' USR1
# ...
gunzip -c "${SVM_IMAGE_FILE_PATH}" | dd iflag=fullblock of="${TARGET_DEVICE_PATH}" bs=64M 2>"${DD_OUTPUT_FILE_PATH}" &
DD_PID=$!
echo "Decompression process has started: $$ -> ${DD_PID}" >> "${DECOMPRESSION_LOG_FILE_PATH}"
# Wait for dd process to become ready to receive 'kill -s USR1' signals
sleep 1
while (ps -p "${DD_PID}") >/dev/null 2>&1
do
set +e
kill -s USR1 $DD_PID 2>/dev/null
LAST_LINE=`tail -n 1 "${DD_OUTPUT_FILE_PATH}"`
case "${LAST_LINE}" in
*byte*)
BYTES_COPIED=`echo ${LAST_LINE} | cut -d ' ' -f1`
PROGRESS=$(( $(( $BYTES_COPIED * 100 )) / $DECOMPRESSED_FILE_SIZE ))
set_status "${PROGRESS}% processed"
;;
esac
# ...
set -e
sleep 1
done
正如您所看到的,sleep 1
循环之前有一个存档while
。我想摆脱它,但我不知道如何。如果我删除此sleep 1
,dd
进程将在第一次调用kill -s USR1 $DD_PID
后立即被终止。也许这并不能杀死dd
,但它会以某种方式影响gunzip
进程 - 我不知道到底发生了什么。
那么,有没有办法摆脱sleep 1
?
答案 0 :(得分:1)
有两个问题:
DD_PID
是运行管道的shell的pid,而不是dd
。SIGUSR1
尚未准备好接收信号,dd
会终止该进程。 shell可以选择在与优化相同的过程中执行/bin/sh
,但这不是您可以依赖的(特别是在使用dd
时不会。
你也不能依靠status=progress
比赛来设置信号陷阱,所以最好自己设置它。
由于您使用的是Linux,请考虑使用GNU dd标志#!/bin/bash
作为自动状态栏。
或者,将shebang更改为trap '' USR1 # Ignore USR1 in inherited processes by default
dd iflag=fullblock of="${TARGET_DEVICE_PATH}" bs=64M 2>"${DD_OUTPUT_FILE_PATH}" \
< <(gunzip -c "${SVM_IMAGE_FILE_PATH}") &
dd_pid=$! # Is now 'dd's pid and not a shell's.
并使用:
sh
或符合fifo="/tmp/foo"
mkfifo "$fifo"
gunzip -c "${SVM_IMAGE_FILE_PATH}" | {
trap '' USR1
dd iflag=fullblock of="${TARGET_DEVICE_PATH}" bs=64M 2>"${DD_OUTPUT_FILE_PATH}" &
echo "$!" > "$fifo"
wait
} &
read dd_pid < "$fifo"
rm "$fifo"
:
dash
或者使用#!/bin/dash
,将shebang更改为trap 'true' USR1
并将trap '' USR1
更改为#initiallyHidden
。