Skip to content
Latchkey

xxd: Hex Dump and Build Binary Fixtures in CI

xxd prints a hex-plus-ASCII dump of a file, and xxd -r turns a hex dump back into raw bytes.

When a "looks identical" file still fails, xxd shows the real bytes: a UTF-8 BOM, a stray CR, or a trailing NUL. Its -r mode also rebuilds committed hex into a binary fixture.

What it does

xxd reads a file (or stdin) and prints each row as an offset, the hex bytes, and the printable ASCII. It ships with Vim, so it is present on almost every runner. Great for spotting a ef bb bf BOM or 0d 0a (CRLF) line endings. With -r it reverses a dump back to raw bytes.

Common usage

Terminal
xxd file.bin | head
# first 64 bytes only
xxd -l 64 file.bin
# start at byte offset 0x100
xxd -s 0x100 file.bin
# plain hex, no offsets or ASCII (pipe-friendly)
xxd -p file.bin
# check for a UTF-8 BOM at the start
xxd -l 3 file.txt

Build a binary fixture with -r

Binary test fixtures are awkward in git. Commit the hex and rebuild the binary in CI with xxd -r -p, which keeps diffs readable. A -p (plain) dump must be reversed with -r -p; a default canonical dump reverses with plain -r.

Round-trip fixture example

Terminal
# create a 4-byte binary fixture from plain hex
echo "1f8b0800" | xxd -r -p > magic.gz.head
# round-trip: dump then rebuild an identical file
xxd -p original.bin > fixture.hex
xxd -r -p fixture.hex > rebuilt.bin
cmp original.bin rebuilt.bin && echo "identical"
# build a PNG signature fixture
printf '89504e470d0a1a0a' | xxd -r -p > png-sig.bin

Options

FlagWhat it does
-l <len>Dump at most len bytes
-s <off>Start at byte offset (accepts 0x hex)
-g <n>Group output into n-byte columns (default 2)
-c <n>Bytes per output line (default 16)
-pPlain postscript-style continuous hex, no offsets
-uUse uppercase hex digits
-rReverse: convert a hex dump back to binary

In CI

To assert a downloaded file starts with the expected magic bytes, dump the head and grep: xxd -l 4 -p artifact.gz should print 1f8b0800 for a gzip. This catches an HTML error page saved under a .gz name before a later step fails cryptically. Commit small binary fixtures as .hex and regenerate them with xxd -r -p so reviewers see a real diff instead of "Binary files differ".

Common errors in CI

"xxd: command not found" appears on minimal images that omit Vim; install it (apt-get install -y xxd or the vim-common/xxd package, apk add xxd on Alpine) or fall back to od -A x -t x1z. Piping xxd file > out without -p writes the formatted dump, not raw bytes. When a rebuilt fixture is empty or the wrong length, the dump format and the reverse flags disagree (a -p dump needs -r -p); odd numbers of hex digits or non-hex characters are silently skipped and drop bytes without an error.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →