21 August 2025
Today I learned how od -c
can save you hours when tracking down a deceptively simple whitespace issue in a Makefile. The culprit? A hidden trailing space that was invisible in my text editor but wreaking havoc on variable assignments. That one invisible trailing space...
I was working on a Makefile with a volume name variable that looked correct:
VOL := $(shell basename "$(PWD)" | tr -d '[:space:]')_usr # space-stripped volume name
But when I ran make snapshot-usr
, I saw:
>> Creating snapshot .usr_snapshot.tar.gz from volume 'sig_usr '
Notice the trailing space after sig_usr
? That space shouldn't be there, and it was causing issues downstream.
First, I tested the shell command directly:
$ basename "$PWD" | tr -d '\n' | od -c
s i g
The command correctly produced sig
with no trailing whitespace. So the issue wasn't with the shell logic.
$ echo "$(basename "$PWD" | tr -d '\n')_usr" | od -c
s i g _ u s r \n
This also looked correct - just sig_usr
followed by a newline from echo. The trailing space had to be coming from somewhere else.
make -n
RevelationUsing make -n
to see what commands would actually run:
$ make -n snapshot-usr | grep "echo.*volume"
echo ">> Creating snapshot .usr_snapshot.tar.gz from volume 'sig_usr '"
There it was! The trailing space was definitely in the VOL variable. But where?
od -c
BreakthroughThe key insight came from using od -c
(octal dump with character format) on the Makefile itself:
$ sed -n '6p' Makefile | od -c
0000000 V O L ? = $ ( s h
0000020 e l l b a s e n a m e " $ $
0000040 P W D " | t r - d ' \ n
0000060 ' ) _ u s r # s p a c e - s
0000100 t r i p p e d v o l u m e n
0000120 a m e \n
Look closely at the output around _usr
. Can you see it?
_ u s r #
There's a space character between r
and #
... that trailing space was being included in the VOL variable definition.
Simple fix, just remove the trailing space:
# Before (with trailing space)
VOL ?= $(shell basename "$$PWD" | tr -d '\n')_usr # comment
# After (space removed)
VOL ?= $(shell basename "$$PWD" | tr -d '\n')_usr
od
Unlike the xxd
or hexdump
commands, the od
command is included in the POSIX specification, so you'll find it installed in many systems without relying on third-party package managers.
The next time you see unexpected behavior in a Makefile, remember: sometimes the bug is hiding in plain sight, invisible to the naked eye! 🔍 And knowing that sweet sweet command-line fu can save you HOURS of debugging.
blog comments powered by Disqus