![如何用随机位或零覆盖设备的开头?](https://linux22.com/image/91223/%E5%A6%82%E4%BD%95%E7%94%A8%E9%9A%8F%E6%9C%BA%E4%BD%8D%E6%88%96%E9%9B%B6%E8%A6%86%E7%9B%96%E8%AE%BE%E5%A4%87%E7%9A%84%E5%BC%80%E5%A4%B4%EF%BC%9F.png)
只是想用零或随机位覆盖设备的一小部分。更准确地说,我想覆盖所有扇区的前 1% 或几个 MiB。有没有一种简单的方法可以做到这一点?
答案1
尽管/dev/urandom
速度非常慢并且因此不适合覆盖大量数据(整个磁盘),但它可能适合小区域。
覆盖 8MiB 的示例:
dd bs=1M count=8 iflag=fullblock if=/dev/urandom of=/dev/destroyme
或者您可以使用shred
:
shred -v -n 1 -s 8M /dev/destroyme
您还可以用来losetup
创建特定大小和偏移量的设备,并使用没有自己的大小/偏移量选项的实用程序覆盖它们。
losetup --find --show --offset 0 --sizelimit $((8*1024*1024)) /dev/destroyme
# will print /dev/loopX
cat /dev/urandom > /dev/loopX
losetup -d /dev/loopX
答案2
与任何文件相同,用零覆盖前 10 MiB:
head -c10M < /dev/zero 1<> /dev/sdax
对于块设备文件,1<>
甚至不需要不截断地打开,因为不存在截断块设备这样的事情,所以您可以简单地执行以下操作:
head -c10M < /dev/zero > /dev/sdax
并非所有头实现都支持-c
,并且当它们支持时,并非所有都支持该M
后缀(当它们支持时M
可能意味着兆字节(1000000 字节),如ksh93
内置head
的或兆字节(1048576 字节),如 GNU head
)。在这种情况下,您可以执行以下操作:
head -c "$((10 * 1024 * 1024)"
使其明确。
如果我们比较dd bs=1M count=10 < /dev/zero > /dev/sdax
:
从概念上来说
head
是从文件中读取指定数量的字节或行并将其写入 stdout 的命令- while
dd
是一个低级命令,可以按照您想要的方式读取和写入数据。
我在这里使用
head
它是因为它是为该任务设计的命令。dd
如果我想针对特定用例进行优化,或者使用特定功能之一dd
(另请参阅有关可移植性的注释),我会使用它。读+写循环:
head -c10M
无论如何,都会尝试读取请求的数据,并且如果遇到错误,只会以非零退出状态失败。dd bs=1M count=10
,将执行 10 次读取(只要没有错误),并且对于返回一些数据的每次读取,使用读取的数据量执行相应的写入。仅当每次读取准确返回所请求的 1M 数据时,该方法才有效。实际上,对于 ,这是正确的/dev/zero
,但在 Linux(至少 4.6)上,对于/dev/urandom
,我无法在一次读取中获得超过 32MiB 减去 1 字节的数据(所以对于 1MiB 来说仍然可以,但如果你使用不同的版本,YMMV Linux 的),而对于/dev/random
,只有几个字节(当前在熵池中的内容)。 GNU 实现dd
具有iflag=fullblock
持续读取直到请求缓冲区已满的行为head
,但如果您没有 GNUdd
,唯一的选择是一次执行 1 个字节读取,这会对性能产生巨大影响。
性能:除了少量数据(少于几百兆字节)以外的任何数据(其中数据被写入稍后将刷新到磁盘的缓冲区或写入 )
/dev/null
,该过程将受到 I/O 限制。如果读取/dev/urandom
或/dev/random
瓶颈将是随机数生成或磁盘 I/O。在这些情况下,您不会发现 dd 和 head 之间有太大区别。在任何情况下都head
可能有更高的 CPU 开销(当性能受到 I/O 限制时不会被注意到)。head
是一个基本工具。实现将尝试尽可能高效地完成工作,同时仍然对所有类型的输入和输出都是可靠的,并且不会使用太多资源。它将执行与 相同的读+写循环dd
,性能方面的主要区别是读取和写入的大小,这将决定进行的系统调用的数量。这些大小将取决于系统的实现和版本,
head
也可能取决于系统。在我的系统上使用最新版本的 GNU 时head
,读取大小为 BUFSIZE(GNU 系统上为 8KiB),写入大小为 4KiB,尽管可以更改stdbuf -o 1M
。ksh93
的head
内置函数似乎可以进行 64KiB 的读取和写入,并且不使用 libc 的 stdio,至少在我的系统上是这样。GNU
head
使用 stdio 也意味着 stdio 产生额外的开销(其实现取决于系统)。当前版本的 GNU
cat
用于fadvise
告诉系统它将按顺序读取数据,以便相应地优化缓存。某些实现head
也可以做到这一点,或者将来也可以做到这一点,这并非不可能。dd
由于是低级别的,我希望它只有在您告诉它的情况下才会执行(我不知道有任何dd
实现具有此类支持)。dd
级别非常低,它会直接调用read()
和write()
系统调用。除了使用 Linux 等专门的 API 之外,您无法获得比这更高的效率sendfile()
。read()
它使您可以更好地控制和的大小write()
,因此可以让您根据输入/输出的类型和可用资源进行优化。例如,如果您有大量可用内存,您不妨一次性读取整个数据(尽管在我的测试中,从 /dev/zero 复制到 /dev/null 时,我看不到过去任何显着的改进)块大小为 32KiB,性能甚至在块大小为 1MiB 之后开始下降)。
可移植性
-c
、bs=10M
、都不conv=fullblock
是便携式的。从文件中读取一定量数据的唯一 POSIX 命令是dd
,但是要可靠地使用它(除了 on/dev/zero
),如上所述,您需要bs=1
这意味着可怕的性能。写入错误的后果。
当尝试写入超过块设备末尾时,
head
和都会立即退出。dd
如果磁盘有故障扇区,通常不会检测到,因为实际写入磁盘是异步的。通过 GNU 实现dd
,您可以强制直接写入,oflag=direct
这意味着dd
将在出现第一个错误时停止。如果您想在第一个失败扇区之前写入尽可能多的数据,您可能需要使用默认块大小 512。读取错误的后果
您不应在 /dev/zero、/dev/urandom 或 /dev/random 上收到任何读取错误。但更一般而言,
head
和dd
都会在第一次读取错误时退出并出现错误。使用dd
,您可以使用 继续错误conv=noerror
。在这种情况下,您可能需要添加选项sync
(conv=noerror,sync
),以便用零填充失败的块。head
不会给你任何选择来做到这一点,因为它不是为此设计的。
备择方案。
pv -Ss 10M < /dev/zero > /dev/sdax
将复制这 10M 并给你一个进度条。在我的测试中,默认读/写大小为 128KiB。您可以使用选项更改它-B
,但在我的测试中,128KiB 已经给出了最佳结果。pv
有一个-E
相当于dd
s 的选项conv=noerror,sync
。在 Linux 上,它也有利于管道上的 I/O,因为它使用
splice()
系统调用来优化性能。如果你想玩
sendfile()
系统调用,你可以使用xfs_io
.xfs_io -c 'sendfile -i src 0 10M' dst
从 src 向 dst 发送 10M 数据。然而,它只做一
sendfile()
并且系统调用不能在/dev/zero
,/dev/random
或上使用/dev/urandom
。但它可以用于稀疏文件。truncate -s 1T empty-file xfs_io -c 'sendfile -i empty-file 0 10M' /dev/sdax
可以工作,但对于大量(几吉比字节),因为这是一个
sendfile()
系统调用,必须分配那么多内存,这意味着它的效率会低于dd bs=1M
.理想情况下,我们希望sendfile()
一次执行多个仅几兆字节的操作,但我不知道有任何命令可以做到这一点。对于
/dev/zero
输入,您实际上不需要读您写入的每个块的数据。毕竟,这只是零。创建一个只有零的缓冲区很容易,而无需读取/dev/zero
,并且我们可以在每次写入之间重用它。例如:PERLIO=:unix perl -e '$x = pack("x" . 1024*1024); print $x for 1..10000' > /dev/sdax
perl
写入 10000 MiB比任何重复读取的解决方案效率更高(尽管有开销) /dev/zero
。
答案3
您可以使用将为您提供随机数据的设备dd
来执行此操作。/dev/urandom
一个例子 :
dd if=/dev/urandom of=/dev/sdX bs=1M count=100
这将写入 100MB 的随机数据:
if
是输入文件of
是输出文件bs=1M
块大小为 1Mbytecount
这个块应该被写入多少次
您也可以使用输入文件/dev/zero
或/dev/null
任何其他为您提供数据的文件。该命令将开始在输出文件/设备的开头写入数据。