如何使用 dd 从 USB(Mac/Windows)重新创建安装程序 iso?

如何使用 dd 从 USB(Mac/Windows)重新创建安装程序 iso?

我读过很多“如何将 iso 写入 USB”的问题。我正在寻找一种逆转这个过程的方法。我的问题是关于使用包含 Windows 安装程序或 Mac 安装程序的 USB 棒,并使用它dd来仅读取 USB 中重新创建原始 iso 所需的部分。

场景:
我有一个 Windows 10 2020 年 10 月版 USB,是我在 11 月刻录的。我想使用 将其备份到磁盘dd。类似以下内容:

dd if=/dev/sda of=backup-windows.iso bs=4m

我希望能够将其与原始 iso 进行比较并获得匹配。换句话说,当 ISO 只有 7-8GB 时,我不想制作 64 GB 的 USB 驱动器映像。

答案1

初步说明

本答案介绍了在符合 POSIX 或几乎符合 POSIX 的操作系统中有效的命令,特别是在 Linux 或 macOS 中。这些命令不适用于纯 Windows(但我认为可以调整答案以在 WSL 或 Cygwin 中工作)。


分析

好的,您已将一些图像复制到 USB 驱动器/dev/sdx。通常,您无法仅根据驱动器的内容和属性来完全逆转该过程,因为您不知道要读取多少字节。上限是驱动器的大小(在您的情况下为 64 GB),其他一切都是猜测。驱动器包含字节流,并且没有标记说“在此处停止读取以获取原始图像”。

通过分析分区表(如果有的话),可以进行有益的猜测。但即便如此,您也无法确定原始映像是否更大(末尾有垃圾或非垃圾)。

但是,如果你想将结果与其他图像进行比较,我们就称其为the_other_file。我猜你希望这两幅图像是相同的。要相同,它们必须具有相同的大小。这意味着你知道要读取多少个字节/dev/sdx:确切的字节数the_other_file。你可以通过调用来获取这个数字

wc -c /path/to/the_other_file

或者

</path/to/the_other_file wc -c

注意前者是独立命令,而后者需要 shell(来处理<)。从现在开始我假设你在 shell 中。


复印

如果你的最终目标是比较,那么你不需要复制到常规文件。在决定之前,请阅读整个答案。明确的问题是:

我怎样才能使用从 USB 重新创建安装程序 ISO dd

它似乎dd是从文件读取精确字节数的唯一 POSIX 方法。此方法需要ibs=1,可能会比较慢。要读取N字节:

dd ibs=1 count=N if=/dev/sdx of=image_file

生成的文件是image_file

原始映像是设计为写入块设备的图像,其大小很可能是 512 字节的倍数,也可能是 4096 字节的倍数。ibs那么您可能可以使用更大的值。

如果N精确的ibs您想要使用的某个较大值的倍数,那么您可以使用ibs经过count调整的较大值。后面的数字指定要读取的count=大小的块数。注意:ibs

  • bs指定ibsobs(参见man 1 dd)。
  • bs=4m(从你的例子来看)既不属于也不bs=4M属于POSIX 规范dd。有效后缀为kb。您可能会惊讶于规范还允许采用 形式的字符串AxB。要获得 4 MiB,请使用bs=4kx1k;要获得 4 MB,请使用bs=4000000bs=4000x1000等。
  • 总的来说,Keep Minddd是一个难以正确使用的工具。它存在一些缺陷。请参阅

如果N不是ibs您要使用的某个较大值的精确倍数,则可以使用较大值读取您要读取的大部分内容ibs,并在使用 读取时附加缺失部分ibs=1。这很麻烦,需要一些计算,但从技术上讲仍然是可行的;尽管几乎没有用处。如果您不限于 POSIX,还有更好的方法。

GNUdd支持无论 是什么iflag=count_bytes都会计数字节。此外,它还提供了一个不错的工具来读取精确的字节数。对于您的情况,命令可能是:countibsiflag=fullblockdd

dd bs=4M iflag=fullblock,count_bytes count=N if=/dev/sdx of=image_file

或(避免手动输入N):

dd bs=4M iflag=fullblock,count_bytes count="$(</path/to/the_other_file wc -c)" if=/dev/sdx of=image_file

如果我是你我会使用head -c

head -c "$(</path/to/the_other_file wc -c)" /dev/sdx >image_file

注意wc -c是可移植的(由 POSIX 指定)但head -c不是(尽管我相信headmacOS 支持-c)。


比较

您可以直接比较,而无需创建任何image_file。以下命令是可移植的:

cmp /dev/sdx /path/to/the_other_file

在您的情况下/dev/sdx,设备大于the_other_file。您将收到一条消息(到 stdout)文件不同,或一条消息(到 stderr)EOF on the_other_file。在这两种情况下,退出状态都是1。后一条消息意味着 的开头/dev/sdx与 相同。这是复制到the_other_file后您所期望的结果。the_other_file/dev/sdx

如果您想通过退出状态进行判断(在脚本中很有用),那么您需要确保您正在比较大小相同的文件。这仍然可以在不创建任何文件的情况下实现image_file

head -c "$(</path/to/the_other_file wc -c)" /dev/sdx | cmp - /path/to/the_other_file

(管道的退出状态来自最后一个命令;此处:来自cmp。)注意head -c(仍然)不可移植。如果需要,:)您可以将其替换为可移植的:dd …

dd ibs=1 count="$(</path/to/the_other_file wc -c)" if=/dev/sdx | cmp - /path/to/the_other_file

image_file或者,如上所示创建后,您可以直接image_file比较the_other_file

cmp image_file the_other_file

退出状态0表示文件相同;退出状态1表示文件不相同。

在交互工作时,您可以关注输出(我的意思是 stdout + stderr,即您通常在终端中看到的所有输出)。 的空输出cmp表示文件相同; 的非空输出cmp表示它所说的内容。 注意dd(但不是head)即使没有错误也会打印到 stderr。 我故意写了“空输出cmp",而不仅仅是“空输出”。如有疑问,无论如何都要检查退出状态:echo $?紧接着运行cmp(或以 结尾的管道之后运行cmp)。

相关内容