opscape

Disks and filesystems

dd

Copy bytes between files or devices in fixed-size blocks, with optional offsets and conversions.

dd [OPERAND...]   (if=FILE of=FILE bs=BYTES count=N skip=N seek=N conv=LIST status=LEVEL)

9 of 11 examples run in Debian 13.7 on 2026-10-31 · coreutils 9.7-3 · manual: dd(1)

dd copies data from an input (if=, default standard input) to an output (of=, default standard output) in blocks of bs bytes. Its syntax is unusual, key=value operands instead of options, because it predates the Unix conventions. What makes it useful is the control: copy exactly count blocks, start skip blocks into the input, write seek blocks into the output, or patch bytes in place with conv=notrunc.

Its best-known job is writing disk images to USB sticks and SD cards (dd if=image.iso of=/dev/sdX bs=4M status=progress). It is also the classic tool for making a file of a given size from /dev/zero or /dev/urandom and for pulling a byte range out of a binary file.

dd writes to whatever of= names without asking. Pointing it at the wrong device overwrites that disk, which is why people call it "disk destroyer". Check the device name with lsblk first, every time. For plain file copies, cp is simpler and usually faster.

Examples

Create a file of a given size

dd if=/dev/zero of=zeros.img bs=1M count=5
ls -l zeros.img
output
5+0 records in
5+0 records out
5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.00191797 s, 2.7 GB/s
-rw-r--r-- 1 dev dev 5242880 Oct 31 20:19 zeros.img

Five 1 MiB blocks of zero bytes. dd reports full and partial records read and written (5+0) and the throughput on standard error.

Random bytes for a key or test data

dd if=/dev/urandom of=key.bin bs=32 count=1 status=none
xxd key.bin
output
00000000: 77bc fbe1 0b2f 7030 e21a 1eb9 bec2 e881  w..../p0........
00000010: 8913 dce0 f3d2 3438 d149 b08d 21b8 bf6f  ......48.I..!..o

32 random bytes, different on every run. status=none silences the statistics, which is what you want inside scripts.

Read the first bytes of a file

dd if=photos/beach.png bs=1 count=8 status=none | xxd
explain
output
00000000: 8950 4e47 0d0a 1a0a                      .PNG....

count=8 with bs=1 copies exactly 8 bytes: the PNG signature, \x89PNG\r\n\x1a\n. head -c 8 does the same for this simple case.

Extract a byte range from the middle

dd if=data/poem.txt bs=1 skip=4 count=15 status=none; echo
explain
output
quick brown fox

skip=4 skips 4 input blocks (bytes, with bs=1) and then 15 are copied: quick brown fox. With large files use a big bs or the byte-granular flags shown below, since bs=1 is slow.

Byte offsets with a large block size

dd if=access.log iflag=skip_bytes,count_bytes skip=1000 count=60 status=none; echo
explain
output
92.0.2.55 - - [14/Mar/2026:08:09:16 +0000] "GET /favicon.ico

iflag=skip_bytes,count_bytes makes skip and count byte counts while dd keeps reading in efficient blocks. The output starts at byte 1000, in the middle of a log line.

Overwrite bytes in place

printf 'version=1.0\n' > app.ini
printf '2' | dd of=app.ini bs=1 seek=8 conv=notrunc status=none
cat app.ini
output
version=2.0

seek=8 positions the output at byte 8 (the 1), and conv=notrunc stops dd from truncating the rest of the file. Without notrunc the file would end right after the new byte.

Convert case while copying

dd if=data/poem.txt conv=ucase status=none
explain
output
THE QUICK BROWN FOX
JUMPS OVER THE LAZY DOG.
THE DOG SLEEPS;
THE FOX RUNS ON.

conv=ucase upper-cases ASCII letters. It is a relic of dd's tape-conversion past; tr a-z A-Z is the usual tool.

Show progress for a long copy

dd if=/dev/zero of=big.img bs=1M count=200 status=progress
explain
output
200+0 records in
200+0 records out
209715200 bytes (210 MB, 200 MiB) copied, 0.044903 s, 4.7 GB/s

status=progress prints a running byte count to standard error while copying. This copy finishes too quickly for an update to appear, so only the final summary is shown.

Read full blocks from a pipe

seq 100000 | dd bs=4096 count=2 iflag=fullblock status=none | wc -c
explain
output
8192

A read from a pipe can return fewer bytes than bs, and count counts reads, not bytes. iflag=fullblock makes dd keep reading until each block is full, so you get exactly 8192 bytes.

Write an image to a USB stick

sudo dd if=debian.iso of=/dev/sdX bs=4M status=progress oflag=sync
explain

Not run in the sandbox: writes to a real block device and needs root; the sandbox has neither. No output is shown because none was captured.

Replace /dev/sdX with the whole device (not a partition like /dev/sdX1) after checking it with lsblk. oflag=sync makes progress reflect what has reached the device, and the copy is only safe to unplug once dd exits.

Back up the first sector of a disk

sudo dd if=/dev/sda of=mbr.bin bs=512 count=1
explain

Not run in the sandbox: reads a real disk device as root. No output is shown because none was captured.

On a disk with an MBR partition table, the first 512 bytes hold the boot code and the partition table (GPT disks keep a "protective" MBR there and their real table just after). Restoring is the same command with if and of swapped, and just as dangerous.

Common pitfalls

  • of=/dev/sdb when you meant /dev/sdc destroys a disk. Run lsblk immediately before, and unplug other removable drives.

  • Without conv=notrunc, writing to an existing regular file truncates it after the last byte written.

  • bs=1 is extremely slow on large ranges; use a big bs with iflag=skip_bytes,count_bytes, or tail -c +N | head -c M.

  • dd does not flush caches by default; a USB stick can still be receiving data after the prompt returns. Add oflag=sync or conv=fsync, or run sync.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • iflag=fullblock and the *_bytes flags are GNU. status=progress is GNU too (newer FreeBSD has it); on macOS, pressing Ctrl-T during a copy prints progress on any version. macOS users also write bs=4m (lowercase suffix) and use /dev/rdiskN for fast raw writes.

Options worth knowing

A selection, described in our own words. For the full list, see dd(1) or dd --help.

OptionWhat it does
if FILERead from FILE instead of standard input.
of FILEWrite to FILE instead of standard output.
bs BYTESRead and write BYTES at a time (suffixes K, M, G).
ibs BYTESRead BYTES at a time.
obs BYTESWrite BYTES at a time.
count NCopy only N input blocks.
skip NSkip N input blocks before copying.
seek NSkip N output blocks before writing.
conv LISTConversions: notrunc, fsync, sync, noerror, ucase, lcase, sparse, ...
iflag FLAGSInput flags: fullblock, skip_bytes, count_bytes, direct, ...
oflag FLAGSOutput flags: sync, dsync, direct, append, seek_bytes, ...
status LEVELnone, noxfer or progress.

Related