Совсем не понимаю аргументы команды dd - PullRequest
12 голосов
/ 22 июля 2011

Я немного знаком с командой dd, но мне редко приходилось использовать ее самостоятельно. Сегодня мне нужно, но я сталкиваюсь с поведением, которое кажется действительно странным.

Я хочу создать 100М текстовый файл, каждая строка которого содержит одно слово «тестирование». Это была моя первая попытка:

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=1M count=100
0+100 records in
0+100 records out
561152 bytes (561 kB) copied, 0.00416429 s, 135 MB/s

Хм, это странно. А как насчет других комбинаций?

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=100K count=1K
0+1024 records in
0+1024 records out
4268032 bytes (4.3 MB) copied, 0.0353145 s, 121 MB/s

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=10K count=10K
86+10154 records in
86+10154 records out
42524672 bytes (43 MB) copied, 0.35403 s, 120 MB/s

~$ perl -e 'print "testing\n" while 1' | dd of=X bs=1K count=100K
102400+0 records in
102400+0 records out
104857600 bytes (105 MB) copied, 0.879549 s, 119 MB/s

Итак, из этих четырех, очевидно, эквивалентных команд, все производят файлы разных размеров, только одну из которых я бы ожидал. Почему это так?

РЕДАКТИРОВАТЬ: Кстати, я немного смущен, я не думал о «да тестирование» вместо этой более длинной команды Perl.

Ответы [ 3 ]

7 голосов
/ 22 июля 2011

Чтобы увидеть, что происходит, давайте посмотрим на вывод strace для аналогичного вызова:

execve("/bin/dd", ["dd", "of=X", "bs=1M", "count=2"], [/* 72 vars */]) = 0
…
read(0, "testing\ntesting\ntesting\ntesting\n"..., 1048576) = 69632
write(1, "testing\ntesting\ntesting\ntesting\n"..., 69632) = 69632
read(0, "testing\ntesting\ntesting\ntesting\n"..., 1048576) = 8192
write(1, "testing\ntesting\ntesting\ntesting\n"..., 8192) = 8192
close(0)                                = 0
close(1)                                = 0
write(2, "0+2 records in\n0+2 records out\n", 31) = 31
write(2, "77824 bytes (78 kB) copied", 26) = 26
write(2, ", 0.000505796 s, 154 MB/s\n", 26) = 26
…

В результате dd делает одиночный read() вызов для чтения каждого блока. Это уместно при чтении с ленты, для которой изначально использовался dd. На лентах read действительно читает блок. При чтении из файла вы должны быть осторожны, чтобы не указывать слишком большой размер блока, иначе read будет усечен. При чтении из канала хуже: размер читаемого блока будет зависеть от скорости команды, производящей данные.

Мораль этой истории не в том, чтобы использовать dd для копирования данных, за исключением безопасных небольших блоков. И никогда из трубы, кроме как с bs=1.

(GNU dd имеет флаг fullblock, указывающий, что он должен вести себя достойно. Но другие реализации этого не делают.)

7 голосов
/ 22 июля 2011

Я пока не уверен, почему, но использование этого метода не заполнит весь блок перед его сохранением. Попробуйте:

perl -e 'print "testing\n" while 1' | dd of=output.txt bs=10K count=10K iflag=fullblock
10240+0 records in
10240+0 records out
104857600 bytes (105 MB) copied, 2.79572 s, 37.5 MB/s

Кажется, что iflag=fullblock заставляет dd накапливать ввод до тех пор, пока блок не заполнится, хотя я не уверен, почему это не по умолчанию, или что он на самом деле делает по умолчанию.

2 голосов
/ 22 июля 2011

Мое лучшее предположение состоит в том, что dd читает из канала, и когда он пуст, он предполагает, что он прочитал весь блок. Результаты весьма противоречивы:

$ perl -e 'print "testing\n" while 1' | dd of=X bs=1M count=100
0+100 records in
0+100 records out
413696 bytes (414 kB) copied, 0.0497362 s, 8.3 MB/s

user@andromeda ~
$ perl -e 'print "testing\n" while 1' | dd of=X bs=1M count=100
0+100 records in
0+100 records out
409600 bytes (410 kB) copied, 0.0484852 s, 8.4 MB/s
...