my Makefile:
foo:
echo -n "d41d8cd98f00b204e9800998ecf8427e" | openssl dgst -md5 -hmac "1@123456"
when I run: make foo
, the output is different from the result of running the same command directly on the shell.(mac m2 arm64)
MacBook-Air:tmp $ make foo
echo -n "d41d8cd98f00b204e9800998ecf8427e" | openssl dgst -md5 -hmac "1@123456"
b6977416b3597483a9e416f4c04a1dcd
MacBook-Air:tmp$ echo -n "d41d8cd98f00b204e9800998ecf8427e" | openssl dgst -md5 -hmac "1@123456"
44ac6a36a27b1e5352a14e803929516f
But when I execute the same operation in an amd64 Ubuntu environment, the results are consistent.
tmp$ make foo
echo -n "d41d8cd98f00b204e9800998ecf8427e" | openssl dgst -md5 -hmac "1@123456"
MD5(stdin)= 44ac6a36a27b1e5352a14e803929516f
echo -n "d41d8cd98f00b204e9800998ecf8427e" | openssl dgst -md5 -hmac "1@123456"
MD5(stdin)= 44ac6a36a27b1e5352a14e803929516f
I am grateful for your guidance.
The echo
command is built into the shell, so its behavior depends upon that shell, which is different between platforms. And make
by default runs /bin/sh
rather than whatever $SHELL
is set to in the environment.
If you remove the openssl
command you can see the behavior difference clearly - the sh
echo on macOS doesn't understand -n
as an option, but just includes it in the output¹. You can reproduce the behavior like so:
$ /bin/sh -c 'echo -n d41d8cd98f00b204e9800998ecf8427e'
-n d41d8cd98f00b204e9800998ecf8427e
(A complicating factor is that make
tries to be smart about when it needs the shell and when it can get away with just exec()
ing the command directly - so a plain echo
with no pipe may do the latter and wind up running /bin/echo
, which even on a Mac understands -n
just fine. But any complications to the command will result in it being run by the shell.)
You could set SHELL
inside the Makefile
, but that introduces its own set of portability problems; if you set it to /bin/zsh
, for instance, the Makefile won't run on systems that don't have zsh
installed, or have it in installed in /usr/bin
or /usr/local/bin
.
I would change the echo -n
to printf
; that way it's consistent across shells, and printf
already doesn't append a newline. In fact, it's probably a good idea to just forget echo
exists and always use printf
instead (just with a \n
on the end when you do want the newline).
But if you'd rather set SHELL
, I would do so with something like this:
SHELL := $(shell echo "$$SHELL")
That tells make
to use whatever the environment variable is set to, which will normally be what the calling shell is.
¹ The Bash 3.2 that ships with macOS changes its echo
behavior when invoked as sh
. Newer versions have stopped doing that, even with POSIXLY_CORRECT set, because while the POSIX standard specifies that echo
shouldn't recognize -n
, it also straight up admits echo
is non-portable and says that it should be avoided except in unambiguous cases – i.e. you want to echo things literally and add a newline and there are no arguments that look like options or backslash escapes.