dd — Block-level copy and convert — disk imaging, raw I/O, test files across all 5 shells
Equivalents in every shell
dd if=input.bin of=output.bin bs=1M status=progressBlock-level copy. `if=` input file, `of=` output file, `bs=` block size, `count=` block count. `status=progress` (GNU coreutils) prints throughput / ETA to stderr while running — without it `dd` is silent until completion. Send SIGUSR1 (`kill -USR1 <pid>`) on older `dd` to force a one-shot progress line.
dd if=input.bin of=output.bin bs=1M status=progressSame `/bin/dd`. macOS `dd` is BSD-derived — `status=progress` is NOT supported (BSD lacks it); the equivalent on macOS is to `kill -INFO <pid>` from another terminal, which prints one progress line. Or install `coreutils` via Homebrew and use `gdd`.
dd if=input.bin of=output.bin bs=1M status=progressSame external binary. Fish parses `bs=1M` as a single argument — no special quoting. `1M` is 1024×1024 in GNU `dd`; use `1MB` for the 1000×1000 SI unit. Common bug: writing `bs = 1M` (with spaces) — `dd` then sees three arguments and complains about unknown operand.
[IO.File]::WriteAllBytes("output.bin", [byte[]]::new(1MB))No native `dd` cmdlet. For file-to-file byte copies: `[IO.File]::Copy("in.bin","out.bin")`. For "fill a file with zeros": `fsutil file createnew zeros.bin 1048576` (Windows builtin, creates a SPARSE file with bytes-on-demand). For real block-device imaging (writing an .iso to a USB stick), no PowerShell-native path exists — use the `dd` build from Cygwin / Git for Windows or invoke `wsl dd …`.
fsutil file createnew zeros.bin 1048576cmd has no native `dd`. `fsutil file createnew <path> <bytes>` creates a sparse file of the requested length (instant, regardless of size). For writing real bytes, `copy /b a.bin + b.bin out.bin` concatenates two binary files. Writing an `.iso` to a USB drive from cmd: shell out to `wsl dd if=image.iso of=/dev/sdX bs=4M` or use the `Rufus` GUI.
Worked examples
Create a 100 MB file filled with zeros (test / scratch)
dd if=/dev/zero of=test.bin bs=1M count=100 status=progressfsutil file createnew test.bin 104857600fsutil file createnew test.bin 104857600Write a bootable ISO to a USB drive (Linux only — destructive)
sudo dd if=ubuntu.iso of=/dev/sdX bs=4M status=progress conv=fsyncImage a partition to a compressed file
sudo dd if=/dev/sda1 bs=4M | gzip > sda1.img.gzwsl bash -c "sudo dd if=/dev/sda1 bs=4M | gzip > /mnt/c/sda1.img.gz"Gotchas
- The historical nickname "disk destroyer" is earned — `of=/dev/sdX` with the wrong device letter wipes the wrong disk in seconds. ALWAYS confirm with `lsblk` (or `diskutil list` on macOS) immediately before running. Tip: paste the entire `dd` line into the terminal but DELETE the leading `sudo ` while you re-check the device — the device-letter check is the failure mode, not the password prompt.
- `bs=` (block size) tuning matters enormously for throughput — `bs=512` (the default) is often 10–50× slower than `bs=4M` on modern disks. But a too-large `bs` can exceed kernel buffer limits on some kernels (`Cannot allocate memory`). `bs=1M` to `bs=4M` is the safe modern default for full-disk imaging.
- `count=` is in BLOCKS, not bytes — `dd if=/dev/zero of=f bs=1M count=10` creates a 10-MB file, NOT a 10-byte file. Forgetting this is the canonical "why is my test file 100 GB" mistake.
- GNU `dd` accepts `status=progress` only since coreutils 8.24 (2015). BSD `dd` (macOS) never accepted it — send `SIGINFO` from another terminal (`kill -INFO <pid>`) for one-shot progress lines, or install GNU coreutils via Homebrew (`brew install coreutils`) and use `gdd`.
- `dd` writes are NOT durable on exit by default — the kernel page cache may still hold the last megabytes. Pass `conv=fsync` (or follow with `sync`) when imaging removable media; without it, pulling the USB stick the moment `dd` finishes can produce a corrupt image. `oflag=direct` skips the page cache entirely at the cost of throughput.