我的硬盘充满零。
如何使用bash检查硬盘上的所有位是否为零?
我的硬盘充满零。
如何使用bash检查硬盘上的所有位是否为零?
Answers:
od
将用替换同一行的运行*
,因此您可以轻松地使用它来扫描非零字节:
$ sudo od /dev/disk2 | head
0000000 000000 000000 000000 000000 000000 000000 000000 000000
*
234250000
| head
在结尾处添加内容,以便如果发现驱动器未归零,则在产生足够的输出以显示事实后停止运行,而不是将整个驱动器转储到屏幕上。
我已经编写了一个简短的C ++程序来做到这一点,可在此处获得源代码。
要构建它:
wget -O iszero.cpp https://gist.github.com/BobVul/5070989/raw/2aba8075f8ccd7eb72a718be040bb6204f70404a/iszero.cpp
g++ -o iszero iszero.cpp
要运行它:
dd if=/dev/sdX 2>/dev/null | ./iszero
它将输出任何非零字节的位置和值。您可以使用将该输出重定向到文件>
,例如:
dd if=/dev/sdX 2>/dev/null | ./iszero >nonzerochars.txt
您可能想尝试进行更改BUFFER_SIZE
以提高效率。我不确定最佳值是多少。请注意,这也会影响打印进度的频率,这会在一定程度上影响速度(将打印输出输出到控制台很慢)。添加2>/dev/null
以摆脱进度输出。
我知道这没有使用标准bash,甚至没有内置函数,但是它不需要任何额外的特权。@Hennes的解决方案仍然更快(我还没有真正优化任何东西-这是天真的解决方案);但是,这个小程序可以使您更好地了解抽头丢失了多少个字节以及在什么位置。如果禁用进度输出,它仍然会比大多数消费类硬盘驱动器读取速度快(> 150 MB / s),因此这不是一个大问题。
此处提供了更快的版本,输出较少的详细信息。但是,它仍然比@Hennes的解决方案慢一点。但是,此字符将在遇到的第一个非零字符处退出,因此,如果在流的开头附近有一个非零字符,则可能会更快。
在帖子中添加来源以使答案更好地独立:
#include <cstdio>
#define BUFFER_SIZE 1024
int main() {
FILE* file = stdin;
char buffer[BUFFER_SIZE];
long long bytes_read = 0;
long long progress = 0;
long long nonzero = 0;
while (bytes_read = fread(buffer, 1, BUFFER_SIZE, file)) {
for (long long i = 0; i < bytes_read; i++) {
progress++;
if (buffer[i] != 0) {
nonzero++;
printf("%lld: %x\n", progress, buffer[i]);
}
}
fprintf(stderr, "%lld bytes processed\r", progress);
}
fprintf(stderr, "\n");
int error = 0;
if (error = ferror(file)) {
fprintf(stderr, "Error reading file, code: %d\n", error);
return -1;
}
printf("%lld nonzero characters encountered.\n", nonzero);
return nonzero;
}
iszero /dev/sda
而不是要求将脚本与之类似iszero < /dev/sda
?
int main(int argc, char *argv[])
then之后FILE* file = fopen(argv[1], "r");
。正确执行此操作将包括检查参数是否确实存在,错误检查打开是否成功(在之后进行其他ferror
检查fopen
)等,但是对于一次性程序来说麻烦太多了。
gcc
在没有拉下其他软件包的情况下不一定可以在所有Linux发行版中使用。再一次,numpy也不是标准Python包的一部分...
-O3
和-march=native
您可能会看到一些的加速; 应该确保GCC启用了自动矢量化功能,并使用当前CPU可用的最佳功能(AVX,SSE2 / SSE3等)。除此之外,您还可以使用缓冲区大小;使用向量化循环时,不同的缓冲区大小可能更为最佳(我将使用1MB +的内存,当前为1kB)。
@Bob
在聊天中对我()进行ping :chat.stackexchange.com/rooms/118/root-access
扩展Gordon的答案,pv
可以说明这一过程有多远:
$ sudo pv -tpreb /dev/sda | od | head
0000000 000000 000000 000000 000000 000000 000000 000000 000000
*
9.76GiB 0:06:30 [25.3MiB/s] [=================> ] 59% ETA 0:04:56
这似乎是一个效率低下的丑陋解决方案,但是如果您只需要检查一次:
dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"
使用dd从磁盘读取sdX
。(将X替换为您要读取的驱动器),
然后将所有不可打印的零字节转换为我们可以处理的内容。
接下来,我们要么计算可以处理的字节数,然后检查它是否正确(wc -c
用于此目的),要么跳过计数并使用-s
或--squeeze-repeats
将所有多次出现的字符压缩为单个char。
因此dd if=/dev/sdX | tr --squeeze-repeats "\000" "T"
应该只打印一个T。
如果要定期执行此操作,则需要更有效的方法。
如果您只想这样做一次,则此垃圾可能会验证您的普通刮水器是否正常工作并且可以信任它。
仅检查,您会看到列出的任何不匹配的块
sudo badblocks -sv -t 0x00 /dev/sdX
或者使用badblocks来编写它们并进行检查:
sudo badblocks -svw -t 0x00 /dev/sdX
默认的破坏性测试是我选择的安全擦除
sudo badblocks -svw /dev/sdX
如果有人在用0和1交替填充驱动器后能检索到任何东西,那么它们的补码,然后是全1,然后是全0,并且每经过一遍验证就可以了,那么祝他们好运!
还要对新驱动器进行良好的部署前检查
man badblocks
其他选择
并不是说它很快,但是它可以工作...
前段时间我很好奇AIO
。结果是一个示例测试程序,该程序正好检查了的扇区(512字节块)NUL
。您可以将其视为稀疏文件区域检测器的变体。我认为消息来源说明了一切。
NUL
输出了整个文件/驱动器,则显示为0000000000-eof
。请注意,程序中有一个技巧,fin()
没有故意在第107行调用该函数以提供显示的输出。AIO
不像其他方法那么直接,AIO
这可能是使驱动器忙于读取的最快方法,因为NUL
比较是在读入下一个数据块时完成的。(我们可以通过重叠来挤出几毫秒的时间AIO
,但是我真的不认为这值得努力。)true
如果文件可读且一切正常,它将始终返回。false
如果文件不是,则不返回NUL
。NUL
,由于内存缓冲区已经包含,它仍然可以正常工作NUL
。如果有人认为这需要解决,请在第95行中memcmp(nullblock, buf+off, SECTOR)
阅读memcmp(nullblock, buf+off, len-off<SECTOR : len-off : SECTOR)
。但是唯一的区别是,“结束报告”可能有点随机(不是针对完全是的文件NUL
)。memcmp()
所做的更改还解决了不NUL
alloc()
编辑内存的平台上的另一个问题,因为代码不执行此操作。但这只能在小于4 MiB的文件中看到,但是checknul
对于这么小的任务,这显然是过分的;)高温超导
/* Output offset of NUL sector spans on disk/partition/file
*
* This uses an AIO recipe to speed up reading,
* so "processing" can take place while data is read into the buffers.
*
* usage: ./checknul device_or_file
*
* This Works is placed under the terms of the Copyright Less License,
* see file COPYRIGHT.CLL. USE AT OWN RISK, ABSOLUTELY NO WARRANTY.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <aio.h>
#define SECTOR 512
#define SECTORS 40960
#define BUFFERLEN (SECTOR*SECTORS)
static void
oops(const char *s)
{
perror(s);
exit(1);
}
static void *
my_memalign(size_t len)
{
void *ptr;
static size_t pagesize;
if (!pagesize)
pagesize = sysconf(_SC_PAGESIZE);
if (len%pagesize)
oops("alignment?");
ptr = memalign(pagesize, len);
if (!ptr)
oops("OOM");
return ptr;
}
static struct aiocb aio;
static void
my_aio_read(void *buf)
{
int ret;
aio.aio_buf = buf;
ret = aio_read(&aio);
if (ret<0)
oops("aio_read");
}
static int
my_aio_wait(void)
{
const struct aiocb *cb;
int ret;
cb = &aio;
ret = aio_suspend(&cb, 1, NULL);
if (ret<0)
oops("aio_suspend");
if (aio_error(&aio))
return -1;
return aio_return(&aio);
}
static unsigned long long nul_last;
static int nul_was;
static void
fin(void)
{
if (!nul_was)
return;
printf("%010llx\n", nul_last);
fflush(stdout);
nul_was = 0;
}
static void
checknul(unsigned long long pos, unsigned char *buf, int len)
{
static unsigned char nullblock[SECTOR];
int off;
for (off=0; off<len; off+=SECTOR)
if (memcmp(nullblock, buf+off, SECTOR))
fin();
else
{
if (!nul_was)
{
printf("%010llx-", pos+off);
fflush(stdout);
nul_was = 1;
}
nul_last = pos+off+SECTOR-1;
}
}
int
main(int argc, char **argv)
{
unsigned char *buf[2];
int fd;
int io, got;
buf[0] = my_memalign(BUFFERLEN);
buf[1] = my_memalign(BUFFERLEN);
if (argc!=2)
oops("Usage: checknul file");
if ((fd=open(argv[1], O_RDONLY))<0)
oops(argv[1]);
aio.aio_nbytes = BUFFERLEN;
aio.aio_fildes = fd;
aio.aio_offset = 0;
io = 0;
my_aio_read(buf[io]);
while ((got=my_aio_wait())>0)
{
unsigned long long pos;
pos = aio.aio_offset;
aio.aio_offset += got;
my_aio_read(buf[1-io]);
checknul(pos, buf[io], got);
io = 1-io;
}
if (got<0)
oops("read error");
printf("eof\n");
close(fd);
return 0;
}
想要从一个类似但较早的问题中发布这个聪明的解决方案,该问题由一段时间未登录的用户发布:
/dev/zero
Linux系统上有一个设备在读取时总是给出零。因此,如何将硬盘驱动器与此设备进行比较:
cmp /dev/sdX /dev/zero
如果将硬盘驱动器清零一切正常,它将终止于:
cmp: EOF on /dev/sdb
告诉您,两个文件在硬盘驱动器末尾之前都是相同的。如果硬盘驱动器上有一个非零位,
cmp
则会告诉您它在文件中的位置。如果已
pv
安装软件包,则:pv /dev/sdX | cmp /dev/zero
将使用进度条执行相同的操作,以使您在检查驱动器时感到很开心(但EOF现在将位于STDIN而不是sdX上)。