makefile执行的结果与shell执行不同

bakd9h0s  于 2023-05-29  发布在  Shell
关注(0)|答案(1)|浏览(183)

我的Makefile:

foo:
    echo -n "d41d8cd98f00b204e9800998ecf8427e" | openssl dgst -md5 -hmac "1@123456"

当我运行:make foo时,输出与直接在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

但是当我在amd64 Ubuntu环境中执行相同的操作时,结果是一致的。

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

我很感激你的指导。

hvvq6cgz

hvvq6cgz1#

echo命令内置在shell中,因此它的行为取决于shell,这在不同平台之间是不同的。默认情况下,make运行/bin/sh,而不是环境中设置的$SHELL
如果删除openssl命令,可以清楚地看到行为差异-macOS上的sh echo不理解-n作为一个选项,但只是将其包含在输出¹中。你可以像这样复制这个行为:

$ /bin/sh -c 'echo -n d41d8cd98f00b204e9800998ecf8427e'
 -n d41d8cd98f00b204e9800998ecf8427e

(一个复杂的因素是,make试图聪明地了解何时需要shell,何时可以直接使用exec()执行命令-所以没有管道的普通echo可能会执行后者并最终运行/bin/echo,即使在Mac上也能很好地理解-n。但是命令的任何复杂性都将导致它由shell运行。)
您可以在Makefile中设置SHELL,但这会引入它自己的一组可移植性问题;例如,如果您将其设置为/bin/zsh,则Makefile将不会在未安装zsh的系统上运行,或者将其安装在/usr/bin/usr/local/bin中。
我会将echo -n更改为printf;这样,它在shell之间是一致的,并且printf已经没有追加换行符。事实上,忘记echo的存在并始终使用printf可能是一个好主意(当您需要换行符时,只需在末尾添加\n)。
但是如果你更愿意设置SHELL,我会这样做:

SHELL := $(shell echo "$$SHELL")

这告诉make使用环境变量的任何设置,这通常是调用shell的内容。
¹ macOS附带的Bash 3.2在作为sh调用时会更改其echo行为。较新的版本已经停止这样做了,即使设置了POSIXLY_CORRECT,因为虽然POSIX标准规定echo不应该识别-n,但它也直接承认echo是不可移植的,并表示应该避免它,除非在明确的情况下-即你想要回显的东西字面上,并添加一个换行符,并没有参数,看起来像选项或反斜杠转义。

相关问题