Невозможно понять аргументы команды dd
Я довольно хорошо знаком с командой dd, но мне редко приходилось использовать ее самостоятельно. Сегодня мне нужно, но я встречаю поведение, которое кажется действительно странным.
Я хочу создать текстовый файл 100M, каждая строка которого содержит одно слово "тестирование". Это была моя первая попытка:
~$ 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.
Ответы
Ответ 1
Я еще не уверен, почему, но использование этого метода не будет заполнять весь блок перед его сохранением. Попробуйте:
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
Чтобы узнать, что происходит, рассмотрим вывод 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
, чтобы он вел себя прилично, но другие реализации этого не делают.)
Ответ 3
Мое лучшее предположение состоит в том, что 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
[email protected] ~
$ 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