tee iso 内容写入 dd 或直接写入 /dev/sda?

tee iso 内容写入 dd 或直接写入 /dev/sda?

一年前,我为有关如何在 Linode 上安装 NixOS 的教程

似乎大多数涉及将 iso 文件放在安装介质上的教程总是使用dd,这就是为什么“现在 dd 还有意义吗?”没有回答我的问题。本教程最初也使用过dd,我对其进行了稍微修改,以获取 sha256 校验和来验证 iso,同时使用 管道从源中传输它tee,如下所示:

curl -L $iso | tee >(dd of=/dev/sda) | sha256sum

但在我看来,dd这里有点多余,而且实际上比下面的慢很多:

curl -L $iso | tee /dev/sda | sha256sum

几个月前,在帮助别人遵循教程时,我记得他们在使用更简单的方法时遇到了问题,但是当我上周末刚刚尝试过两次单独的安装时,它似乎工作得很好,而且速度也相当快。

此修改是否足够可靠,可以提交更新教程的拉取请求?

或者我只是幸运地让它工作,并且dd实际上更安全、更可靠地用于创建安装介质 - 因此我们应该按原样保留教程?

答案1

使用dd并不更安全、更快或更不可靠。事实上,这里引入了两种额外的失败风险。如果人们手动遵循这些说明,这两种风险在实践中都不太可能成为问题,但如果这些说明位于自动化脚本中,则这两种风险都将是严重的错误。

Bug:竞争条件

观察:

bash-5.0$ echo hello | tee >(sleep 1; echo done); echo next step
hello
next step
bash-5.0$ done

在 bash 中,输出过程替换是异步的。当命令包含进程替换时>(…),它不会等待进程替换完成。

因此,当… | tee >(dd of=/dev/sda) | sha256sum返回时,可能有数据仍在通过 传输dd。这不太可能持续足够长的时间以供人类做出反应并键入另一个命令,但它可能会破坏运行其他命令(例如ejectmount之后)的脚本。

Bug:缺少错误检测

让我们开始一个一切正常的名义案例。

bash-5.0$ head -c 1m </dev/zero | tee >(cat >/dev/null) | wc -c; echo $?
1048576
0

现在让我们看看如果数据写入命令失败会发生什么情况。

bash-5.0$ head -c 1m </dev/zero | tee >(false) | wc -c; echo $?
8192
0

该命令具有成功状态,因为管道的退出状态仅取决于右侧。这个想法是,如果将数据生成器通过管道传输到数据处理器,则数据处理器的工作就是检测故障。不幸的是,这仅适用于数据格式允许数据处理器检测故障的情况,但通常情况并非如此,特别是此处并非如此。

请注意,tee一旦无法写入连接到的管道,就彻底放弃false。由于false从未读取任何数据,因此通过 to 的唯一数据wc -c是两个PIPE_BUF(一个tee写入两个管道,另一个tee仅写入管道 towc但未能写入管道 to false)。根据false退出与tee写入管道和wc消耗数据的相对时间,可能只有 1 个或 0 个PIPE_BUF通过。

tee通过设置该选项可以检测到故障pipefail。 (这种可能性存在于 ksh、bash 和 zsh 中,但不存在于普通 sh 中。)

bash-5.0$ set -o pipefail; head -c 1m </dev/zero | tee >(false) | wc -c; echo $?
8192
141

tee无法写入管道,因此它死于 SIGPIPE,对应的 shell 状态为 128 + SIGPIPE 的数值(在 Linux 上为 13)。由于该pipefail选项,这会导致整个管道以相同的状态退出。

请注意,管道反映的是 的失败tee,而不是直接反映进程替换中命令的失败。如果进程替换中的命令成功读取了所有数据但未成功处理,则不会检测到错误。

bash-5.0$ head -c 1m </dev/zero | tee >(cat >/dev/null; false) | wc -c; echo $?
1048576
0

wc -c处理了所有数据。cat >/dev/null; false模拟未正确处理所有输入的命令。尽管如此,该命令的状态表明已成功。

在您的实际示例中,这意味着如果数据末尾存在错误,例如因为目标设备比图像小得多,则不会检测到此错误(除非通过来自 的错误消息dd) 。

简单、正确的解决方案

set -o pipefail
curl -L $iso | tee /dev/sda | sha256sum

或者,可以说更简单:

curl -L $iso | tee >/dev/sda >(sha256sum)

请注意,如果没有pipefail,第二个命令即使curl失败也会成功。然而,这种失败肯定会导致错误的校验和。

关于 dd 使用的一般说明

似乎大多数涉及将 iso 文件放在安装介质上的教程总是使用 dd,这就是为什么“现在 dd 仍然相关吗?”没有回答我的问题

嗯,或多或少确实如此。具体来说,它回答了是否有任何目的的问题dd:没有。它没有涵盖使用dd这种特定方式时遇到的具体问题,这次实际上并不是由于dd其本身。

大多数教程使用的原因dd是大多数教程使用dd.这是一个自我延续的传奇。人们使用它是dd因为他们在其他地方看到过它的使用,尽管他们并不真正理解为什么。它的语法与其他命令不同,因此显得有些神秘和强大。但在dd of=/dev/sda,所有的力量都在/dev/sda,却没有dd。这只是一种自命不凡、脆弱的写作方式cat >/dev/sda

相关内容