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
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.txtBuild 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
# 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.binOptions
| Flag | What 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) |
| -p | Plain postscript-style continuous hex, no offsets |
| -u | Use uppercase hex digits |
| -r | Reverse: 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.