dd实用程序尚未准备好接收终止信号

时间:2017-05-03 17:00:34

标签: linux bash shell dd

我有一个脚本解压缩.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 1dd进程将在第一次调用kill -s USR1 $DD_PID后立即被终止。也许这并不能杀死dd,但它会以某种方式影响gunzip进程 - 我不知道到底发生了什么。

那么,有没有办法摆脱sleep 1

1 个答案:

答案 0 :(得分:1)

有两个问题:

  1. DD_PID是运行管道的shell的pid,而不是dd
  2. 如果
  3. SIGUSR1尚未准备好接收信号,
  4. dd会终止该进程。
  5. 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