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

huangapple go评论100阅读模式
英文:

The result of makefile execution is different from shell execution

问题

Here's the translation of the code part you provided:

我的 Makefile:

```make
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

感谢您的指导。


Please note that the translation above may contain HTML-encoded characters like `"` and `<`, which are used for displaying code in the HTML format.

<details>
<summary>英文:</summary>


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.


  [1]: https://i.stack.imgur.com/ITmUO.png

</details>


# 答案1
**得分**: 3

以下是您要翻译的内容:

"echo"命令是内置于Shell中的,因此其行为取决于所使用的Shell,这在不同平台之间是不同的。而且,默认情况下,"make"运行的是"/bin/sh",而不是环境中设置的"$SHELL"。

如果移除"openssl"命令,您可以清晰地看到行为差异 - macOS上的"sh" echo不理解"-n"作为选项,而是将其包含在输出中。您可以这样复现这个行为:

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


(一个复杂因素是,"make"试图智能判断何时需要Shell以及何时可以直接执行命令 - 因此,没有管道的普通"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的值。

<details>
<summary>英文:</summary>

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&#39;t understand `-n` as an option, but just includes it in the output&#185;. You can reproduce the behavior like so:

     $ /bin/sh -c &#39;echo -n d41d8cd98f00b204e9800998ecf8427e&#39;
     -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&#39;t run on systems that don&#39;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&#39;s consistent across shells, and `printf` already doesn&#39;t append a newline. In fact, it&#39;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&#39;d rather set `SHELL`, I would do so with something like this:

    SHELL := $(shell echo &quot;$$SHELL&quot;)

That tells `make` to use whatever the environment variable is set to, which will normally be what the calling shell is.


&#185; &lt;sup&gt;&lt;sub&gt;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&#39;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.&lt;/sub&gt;&lt;/sup&gt;
 

</details>



huangapple
  • 本文由 发表于 2023年5月25日 18:41:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76331407.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定