49

Я хотел создать случайный файл размером 1 ГБ, поэтому использовал следующую команду.

dd if=/dev/urandom of=output bs=1G count=1

Но вместо этого каждый раз, когда я запускаю эту команду, я получаю файл размером 32 МБ:

<11:58:40>$ dd if=/dev/urandom of=output bs=1G count=1
0+1 records in
0+1 records out
33554431 bytes (34 MB, 32 MiB) copied, 0,288321 s, 116 MB/s

Что случилось?

РЕДАКТИРОВАТЬ:

Благодаря отличным ответам в этой теме я пришел с решением, которое читает 32 блока по 32 МБ, что составляет 1 ГБ:

dd if=/dev/urandom of=output bs=32M count=32

Было дано другое решение, которое считывает 1 ГБ прямо в память, а затем записывает на диск. Это решение занимает много памяти, поэтому оно не является предпочтительным:

dd if=/dev/urandom of=output bs=1G count=1 iflag=fullblock

2 ответа2

92

bs , размер буфера, означает размер одного вызова read(), выполняемого dd.

(Например, оба bs=1M count=1 и bs=1k count=1k приведут к файлу размером 1 МБ, но первая версия сделает это за один шаг, а вторая сделает это за 1024 маленьких фрагмента.)

Обычные файлы могут быть прочитаны практически при любом размере буфера (при условии, что этот буфер помещается в ОЗУ), но устройства и "виртуальные" файлы часто работают очень близко к отдельным вызовам и имеют некоторые произвольные ограничения на объем данных, которые они будут создавать в чтение () вызов.

Для /dev/urandom это ограничение определено в urandom_read() в drivers/char/random.c:

#define ENTROPY_SHIFT 3

static ssize_t
urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
    nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3));
    ...
}

Это означает, что каждый раз, когда вызывается функция, она ограничивает запрошенный размер до 33554431 байта.

По умолчанию, в отличие от большинства других инструментов, dd не будет повторять попытку после получения меньшего количества данных, чем запрошено - вы получаете 32 МБ и все. (Чтобы повторить попытку автоматически, как в ответе Камила, вам нужно указать iflag=fullblock .)


Также обратите внимание, что «размер одного read()» означает, что весь буфер должен помещаться в памяти одновременно, поэтому огромные размеры блоков также соответствуют массовому использованию памяти dd.

И все это бессмысленно, потому что вы обычно не получаете никакой производительности, когда превышаете ~ 16–32 МБ блоков - системные вызовы здесь не медленная часть, а генератор случайных чисел.

Так что для простоты просто используйте head -c 1G /dev/urandom > output .

21

dd может читать меньше, чем ibs (примечание: bs указывает и ibs и obs), если не указано iflag=fullblock . 0+1 records in означает, что 0 полных блоков и 1 частичный блок были прочитаны. Однако любой полный или частичный блок увеличивает счетчик.

Я не знаю точного механизма, который заставляет dd читать блок менее 1G в данном конкретном случае. Я предполагаю, что любой блок считывается в память до его записи, поэтому управление памятью может помешать (но это только предположение). Редактировать: этот параллельный ответ объясняет механизм, который заставляет dd читать блок менее 1G в данном конкретном случае.

Во всяком случае, я не рекомендую такие большие bs . Я бы использовал bs=1M count=1024 . Самое главное: без iflag=fullblock любая попытка чтения может прочитать меньше, чем ibs (если, я думаю, ibs=1 , это довольно неэффективно).

Поэтому, если вам нужно прочитать какой-то точный объем данных, используйте iflag=fullblock . Обратите iflag что если POSIX не требуется, ваш dd может не поддерживать его. Согласно этому ответу, ibs=1 , вероятно, является единственным способом POSIX для считывания точного количества байтов. Конечно, если вы измените ibs вам нужно будет пересчитать count . В вашем случае снижение ibs до 32M или менее, вероятно, решит проблему, даже без iflag=fullblock .

В моем Kubuntu я бы исправил вашу команду следующим образом:

dd if=/dev/urandom of=output bs=1M count=1024 iflag=fullblock

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .