Создайте случайные данные с помощью dd и получите «предупреждение о частичном чтении». Являются ли данные после предупреждения действительно случайными?

16

Я создаю 1 ТБ файл со случайными данными с dd if=/dev/urandom of=file bs=1M count=1000000. Теперь я проверяю kill -SIGUSR1 <PID>прогресс и получаю следующее:

691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s

Я не могу интерпретировать предупреждение. Что это говорит? Мой файл действительно случайный после предупреждения или есть проблема? Что +0 или +1 в 800950+1 Datensätze einи 800950+0 Datensätze ausсредний? После предупреждения это +1. Это ошибка?

удалять
источник
На это было бы легче ответить, если бы вы могли перевести сообщения на английский. Также определите «действительно случайный». Какой уровень случайности вам нужен, для чего вы будете его использовать?
Terdon
Чтобы получать сообщения на английском языке, используйте LC_ALL=Cперед командой, например,LC_ALL=C dd if=...
Volker Siegel,

Ответы:

38

Резюме: ddкапризный инструмент, который трудно использовать правильно. Не используйте его, несмотря на многочисленные уроки, которые говорят вам об этом. ddк нему прикреплена атмосфера «Unix Street Credit» - но если вы действительно понимаете, что делаете, вы будете знать, что вам не следует прикасаться к нему 10-футовым шестом.

ddсовершает один вызов readсистемного вызова на блок (определяется значением bs). Нет гарантии, что readсистемный вызов вернет столько данных, сколько указано в размере буфера. Это работает для обычных файлов и блочных устройств, но не для каналов и некоторых символьных устройств. См. Когда dd подходит для копирования данных? (или, когда read () и write () частично) для получения дополнительной информации. Если readсистемный вызов возвращает менее одного полного блока, то ddпередается частичный блок. Он по-прежнему копирует указанное количество блоков, поэтому общее количество переданных байтов меньше запрашиваемого.

Предупреждение о «частичном чтении» говорит вам именно об этом: одно из чтений было частичным, поэтому ddпередан неполный блок. В подсчете блоков +1означает, что один блок был прочитан частично; так как количество выводов равно +0, все блоки были записаны как прочитанные.

Это не влияет на случайность данных: все ddзаписываемые байты являются байтами, из которых они считывают /dev/urandom. Но вы получили меньше байтов, чем ожидалось.

Linux принимает /dev/urandomпроизвольные большие запросы (source: extract_entropy_userin drivers/char/random.c), поэтому ddобычно безопасен при чтении с него. Однако чтение больших объемов данных требует времени. Если процесс получает сигнал, readсистемный вызов возвращается до заполнения своего выходного буфера. Это нормальное поведение, и приложения должны вызываться readв цикле; ddне делает этого по историческим причинам ( ddпроисхождение мрачное, но, похоже, оно начиналось как инструмент для доступа к лентам, которые имеют особые требования и никогда не были приспособлены для использования в качестве инструмента общего назначения). Когда вы проверяете прогресс, он посылает ddпроцессу сигнал, который прерывает чтение. У вас есть выбор между знанием, сколько байтовdd полная копия воли (убедитесь, что она не прерывается - нет проверки хода выполнения, нет приостановки) или известно, сколько байтdd до сих пор скопировал, и в этом случае вы не можете знать, сколько еще байтов будет скопировано.

Версия ddв GNU coreutils (как в не встроенных Linux и в Cygwin) имеет флаг, fullblockкоторый указывает ddна вызов readв цикле (и то же для write) и, таким образом, всегда передает полные блоки. Сообщение об ошибке предполагает, что вы используете его; Вы должны всегда использовать его (как во входных, так и в выходных флагах), за исключением особых случаев (в основном, при доступе к лентам) - если вы используете ddвообще, то есть: обычно есть лучшие решения (см. ниже).

dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000

Другой возможный способ быть уверенным в том, ddчто нужно сделать, - передать размер блока, равный 1. Затем вы можете сказать, сколько байтов было скопировано из числа блоков, хотя я не уверен, что произойдет, если readпрервать a перед чтением первого байт (что не очень вероятно на практике, но может случиться). Однако, даже если это работает, это очень медленно.

Общие рекомендации по использованию ddявляется не использоватьdd . Хотя ddчасто объявляется как команда низкого уровня для доступа к устройствам, на самом деле это не так: все волшебство происходит в части файла (the /dev/…) устройства, ddэто просто обычный инструмент с высоким потенциалом для неправильного использования, что приводит к потере данных , В большинстве случаев есть более простой и безопасный способ сделать то, что вы хотите, по крайней мере, в Linux.

Например, чтобы прочитать определенное количество байтов в начале файла, просто вызовите head:

head -c 1000000m </dev/urandom >file

Я сделал быстрый тест на моей машине и не заметил различий в производительности между ddбольшим размером блока и head.

Если вам нужно пропустить несколько байтов в начале, отправьте tailв head:

dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output

Если вы хотите увидеть прогресс, позвоните, lsofчтобы увидеть смещение файла. Это работает только для обычного файла (выходного файла в вашем примере), а не для символьного устройства.

lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1

Вы можете позвонить, pvчтобы получить отчет о ходе работы (лучше, чем у dd), за счет дополнительного элемента в конвейере (с точки зрения производительности, он едва заметен).

Жиль "ТАК - прекрати быть злым"
источник
2
+1. Это один из наиболее хорошо изученных постов, которые я читал в сети StackExchange за долгое время. Это краткое, но содержит все детали (исторические и современные) о ddкоманде, которые я не знал, что мне нужно было знать. Благодарю.
Космическое оссиффраж
4
Извините, но я не согласен с вашим утверждением, что dd - это «капризный инструмент, который трудно использовать правильно» и «не используйте dd». Это очень хорошая утилита, если ее правильно использовать кто-то, кто нашел время, чтобы понять ее. Действительно, набор инструментов для криминалистической экспертизы диска почти все зависит от dd или его производной, такой как dcfldd.
fpmurphy
1
@ fpmurphy1 GNU ddможет использоваться безопасно благодаря его fullblockопции. Но если у вас есть GNU coreutils, вам не нужно ddмного. «Производные» такие как неdcfldd являются , они не страдают от своих конструктивных дефектов, поэтому мой ответ к ним не относится. Огромное, подавляющее большинство людей, которые используют , не нашли достаточно времени, чтобы понять это (самое большее, они нашли время, чтобы подумать, что понимают это), и то, как они это используют, приводит к потере данных. dddd
Жиль "ТАК - перестань быть злым"
1
@ Жиль Итак, мы не должны использовать "эхо" b / c из-за его потенциального злоупотребления (sudo echo hello world> / dev / sda)?
whitey04
2
@ whitey04 Я рекомендую не использовать бочки с нитроглицерином. Я не говорил, что вы не должны использовать спички.
Жиль "ТАК - перестань быть злым"
9

Предупреждение возникает, когда ddне удается получить достаточно данных для заполнения блока за одно чтение. Это происходит с ошибочными или медленными источниками данных или источниками, которые записывают данные в меньших единицах, чем запрашиваемый размер блока.

Нет проблем с целостностью данных, но проблема в том, что ddчастичное чтение все еще считается блоком чтения.

Если вы не используете эту countопцию, предупреждение вряд ли имеет значение, это просто соображение производительности. Но при этом countвы не получите объем запрошенных вами данных. Из-за частичного чтения ofбудет меньше, чем count*bsв конце.

Поэтому, когда вы используете count, технически вы должны всегда использовать iflag=fullblockтакже.

+xДолжно быть количество частичных блоков.

frostschutz
источник
-3
< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^ Это будет просто работать. Дезинформация, которая в противном случае была здесь, явно ложна.ddБуферы являются явными, и поэтому для буферизации ввода для подсчета вхождений необходимо явно буферизовать. Это все. Не покупай фуд.

mikeserv
источник