Короткий зміст: dd
це химерний інструмент, який важко правильно використовувати. Не використовуйте його, незважаючи на численні підручники, які вам так говорять. dd
до нього прикріплена вібрація «unix street Credit» - але якщо ви справді зрозумієте, що ви робите, ви знатимете, що не слід торкатися її 10-футовим полюсом.
dd
робить один виклик до read
системного виклику на блок (визначається значенням bs
). Немає гарантії, що read
системний виклик повертає стільки даних, скільки вказаний розмір буфера. Це, як правило, працює для звичайних файлів і блокових пристроїв, але не для труб та деяких пристроїв символів. Дивіться, коли dd підходить для копіювання даних? (або, коли читаються () та записуються () частково) для отримання додаткової інформації. Якщо read
системний виклик повертає менше одного повного блоку, то dd
передає частковий блок. Він все ще копіює вказану кількість блоків, тому загальна кількість переведених байтів менша, ніж потрібно.
Попередження про "часткове зчитування" говорить саме про це: одне з прочитаних було частковим, тому dd
передано неповний блок. У підрахунку блоків +1
означає, що один блок був прочитаний частково; Оскільки підрахунок виходу є +0
, всі блоки записувались як прочитані.
Це не впливає на випадковість даних: усі байти, які dd
виписують, - це байти, з яких вони читаються /dev/urandom
. Але у вас менше байтів, ніж очікувалося.
Linux /dev/urandom
вміщує довільні великі запити (джерело: extract_entropy_user
в drivers/char/random.c
), тому dd
зазвичай безпечно при читанні з нього. Однак для читання великої кількості даних потрібен час. Якщо процес отримує сигнал, read
системний виклик повертається перед заповненням його вихідного буфера. Це нормальна поведінка, і програми повинні викликати read
цикл; dd
цього не роблять з історичних причин ( dd
джерела похмурі, але, здається, він почав бути інструментом доступу до стрічок, які мають особливі вимоги, і ніколи не був адаптований як інструмент загального призначення). Коли ви перевіряєте хід, це надсилає dd
процесу сигнал, який перериває прочитане. У вас є вибір між знанням, скільки байтівdd
буде скопійовано загалом (переконайтеся, що не переривати її - не перевірка ходу, не призупинення) або знаючи, скільки байтів dd
скопійовано до цього часу, і в цьому випадку ви не можете знати, скільки ще байтів буде скопійовано.
У версії dd
GNU coreutils (як це знайдено в невбудованому Linux та Cygwin) є прапор, fullblock
який говорить dd
про дзвінок read
у циклі (та ditto для write
) та таким чином завжди передає повні блоки. Повідомлення про помилку говорить про те, що ви використовуєте його; ви завжди повинні використовувати його (як у вхідних, так і у вихідних прапорах), за винятком дуже особливих обставин (переважно під час доступу до стрічок) - якщо ви dd
взагалі використовуєте , тобто: зазвичай є кращі рішення (див. нижче).
dd if=/dev/urandom iflag=fullblock oflag=fullblock of=file bs=1M count=1000000
Ще один можливий спосіб бути впевненим у тому dd
, що робити, - це передати розмір блоку 1. Тоді ви можете сказати, скільки байтів було скопійовано з підрахунку блоків, хоча я не впевнений, що буде, якщо read
перерватиметься перед читанням першого байт (що на практиці мало ймовірно, але може статися). Однак навіть якщо це працює, це дуже повільно.
Загальну пораду щодо використання dd
- не використовуватиdd
. Хоча dd
це часто рекламується як команда низького рівня для доступу до пристроїв, насправді такого немає: вся магія відбувається у файлі пристрою ( /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
), за рахунок додаткового пункту в конвеєрі (з точки зору продуктивності, це ледь помітно).