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)
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
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
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
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
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
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
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
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
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
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
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
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/sdbwhen you meant/dev/sdcdestroys a disk. Runlsblkimmediately before, and unplug other removable drives.Without
conv=notrunc, writing to an existing regular file truncates it after the last byte written.bs=1is extremely slow on large ranges; use a bigbswithiflag=skip_bytes,count_bytes, ortail -c +N | head -c M.dddoes not flush caches by default; a USB stick can still be receiving data after the prompt returns. Addoflag=syncorconv=fsync, or runsync.
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=fullblockand the*_bytesflags are GNU.status=progressis GNU too (newer FreeBSD has it); on macOS, pressing Ctrl-T during a copy prints progress on any version. macOS users also writebs=4m(lowercase suffix) and use/dev/rdiskNfor fast raw writes.
Options worth knowing
A selection, described in our own words. For the full list, see dd(1) or dd --help.
| Option | What it does |
|---|---|
if FILE | Read from FILE instead of standard input. |
of FILE | Write to FILE instead of standard output. |
bs BYTES | Read and write BYTES at a time (suffixes K, M, G). |
ibs BYTES | Read BYTES at a time. |
obs BYTES | Write BYTES at a time. |
count N | Copy only N input blocks. |
skip N | Skip N input blocks before copying. |
seek N | Skip N output blocks before writing. |
conv LIST | Conversions: notrunc, fsync, sync, noerror, ucase, lcase, sparse, ... |
iflag FLAGS | Input flags: fullblock, skip_bytes, count_bytes, direct, ... |
oflag FLAGS | Output flags: sync, dsync, direct, append, seek_bytes, ... |
status LEVEL | none, noxfer or progress. |
Related
cpCopy files and directories, optionally keeping their timestamps, permissions and links.truncateShrink or extend a file to an exact size, creating it if needed.xxdMake a hex dump of a file, or turn a hex dump back into binary with -r.headPrint the first lines (or bytes) of files; 10 lines by default.lsblkList block devices (disks, partitions, LVM volumes, loop devices) as a tree, with sizes and mount points.