在Makefile中是否应该使用双美元符号来表示Bash Shell变量?

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

Should you use double dollar sign in Makefile for bash shell variables?

问题

This is the Makefile content:

sgr0 := $(shell tput sgr0)
bold := $(shell tput bold)
orange := $(shell tput setaf 166)

test:
    @echo "$(bold)$(orange)ENV_VARIABLE:$(sgr0) $${ENV_VARIABLE}"

You run the following command in bash:

export ENV_VARIABLE=value

Then you call make test and get the following output:

ENV_VARIABLE: value

Instead, if you modify the Makefile test target like this:

test:
        @echo "$(bold)$(orange)ENV_VARIABLE:$(sgr0) $$ENV_VARIABLE"

The result of calling make test would be:

ENV_VARIABLE: $ENV_VARIABLE

UPDATE:
You execute export ENV=test.txt
Makefile content:

test:
    touch $(ENV)

This works as it returns touch test.txt.

Instead, if you change to $$(ENV), it will throw an error.

英文:

This is the Makefile content:

sgr0 := $(shell tput sgr0)
bold := $(shell tput bold)
orange := $(shell tput setaf 166)

test:
	@echo "$(bold)$(orange)ENV_VARIABLE:(sgr0) ${ENV_VARIABLE}"

You run the following command in bash:

export ENV_VARIABLE=value

Then you call call make test and get the following output:

ENV_VARIABLE: value

Instead, if you modify the Makefile test target like this:

test:
    	@echo "$(bold)$(orange)ENV_VARIABLE:(sgr0) $${ENV_VARIABLE}"

The result of calling make test would be:

ENV_VARIABLE: $ENV_VARIABLE

So I'm pretty confused, because the GNU make official doc says to use $$ for shell variables:

> Variable and function references in recipes have identical syntax and
> semantics to references elsewhere in the makefile. They also have the
> same quoting rules: if you want a dollar sign to appear in your
> recipe, you must double it (‘$$’). For shells like the default shell,
> that use dollar signs to introduce variables, it’s important to keep
> clear in your mind whether the variable you want to reference is a
> make variable (use a single dollar sign) or a shell variable (use two
> dollar signs).

But if I use $$, then I don't see how my variable gets expanded. So, in order to follow the best practice of using $$ for shell variables and $ for make variables, I need to give up on being able to read how the shell variable gets expanded?

UPDATE:
You execute export ENV=test.txt
Makefile content:

test:
	touch $(ENV)

this works as it returns touch test.txt

Instead, if you change to $$(ENV), it will throw an error.

答案1

得分: 1

在非常简洁的说法中,你创建的变量是“make”变量。它们在shell运行之前由“make”替换。

如果你希望推迟扩展以便由shell执行,那么是的,你必须使用不同的语法(用双倍的美元符号转义它们,而不需要括号,可能用大括号替换它们)。

export bold sgr0

demo:
	@echo "在shell运行之前,$(bold)加粗$(sgr0)已经被make扩展了"
	@echo "shell也可以做到这一点:$${bold}加粗$${sgr0}"

对于后一个echo生效,你必须包含export行。

当变量已经是一个独立的标记时,大括号是不必要的。所以在上面的例子中,$$sgr0也可以起作用。参见 https://stackoverflow.com/questions/8748831/when-do-we-need-curly-braces-around-shell-variables

如果你尝试$$(bold),那就是一个命令替换,shell将尝试将括号内的文本作为命令运行,并用该命令的输出替换命令替换。如果括号内的文本不是有效的命令,那么当然,你会得到一个错误。

weird:
	@echo "今天是$$(date)"
	@echo "你不希望是一个$$(语法错误)"
英文:

In very brief, the variables you created are make variables. They are substituted by make before the shell runs at all.

If you wanted to defer expansion to be performed by the shell, then yes, you would have to use a different syntax (with the dollar signs escaped by doubling them, and without parentheses, possibly replacing them with braces).

export bold sgr0

demo:
	@echo "Make expanded $(bold)bold$(sgr0) before the shell ran"
	@echo "The shell can do this too: $${bold}bold$${sgr0}"

For the latter echo to work, you have to include the export line.

Braces are unnecessary when the variable is already a separate token. So in the above, $$sgr0 would work too. See also https://stackoverflow.com/questions/8748831/when-do-we-need-curly-braces-around-shell-variables

If you were to try $$(bold), that's a command substitution, where the shell will try to run the text inside the parentheses as a command, and replace the command substitution with the output from that command. If the text inside the parentheses is not a valid command, then of course, you will get an error.

weird:
	@echo "Today is $$(date)"
	@echo "You don't want a $$(syntax error)"

答案2

得分: 1

Sure, here are the translated code parts:

test:
    @echo "ENV_VARIABLE: ${ENV_VARIABLE}"
# Calling with: ENV_VARIABLE=value make
# prints : ENV_VARIABLE: value

Now

test:
    @echo "ENV_VARIABLE: $${ENV_VARIABLE}" # 两个美元符号
# Calling with: ENV_VARIABLE=value make
# prints the same: ENV_VARIABLE: value

So you would be tempted to say $ and $$ are the same, but they aren't.

test:
    @ENV_VARIABLE=value2; echo "ENV_VARIABLE: ${ENV_VARIABLE}"
# Calling with: ENV_VARIABLE=value make
# prints : ENV_VARIABLE: value

but

test:
    @ENV_VARIABLE=value2; echo "ENV_VARIABLE: $${ENV_VARIABLE}"
# Calling with: ENV_VARIABLE=value make
# prints : ENV_VARIABLE: value2
英文:

Let's illustrate with a few examples :

test:
    @echo "ENV_VARIABLE: ${ENV_VARIABLE}"
# Calling with: ENV_VARIABLE=value make
# prints : ENV_VARIABLE: value

Now

test:
    @echo "ENV_VARIABLE: $${ENV_VARIABLE}" # Two dollars
# Calling with: ENV_VARIABLE=value make
# prints the same: ENV_VARIABLE: value

So you would be tempted to say $ and $$ are the same, but they aren't.

test:
    @ENV_VARIABLE=value2; echo "ENV_VARIABLE: ${ENV_VARIABLE}"
# Calling with: ENV_VARIABLE=value make
# prints : ENV_VARIABLE: value

but

test:
    @ENV_VARIABLE=value2; echo "ENV_VARIABLE: $${ENV_VARIABLE}"
# Calling with: ENV_VARIABLE=value make
# prints : ENV_VARIABLE: value2

huangapple
  • 本文由 发表于 2023年4月17日 12:40:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031761.html
匿名

发表评论

匿名网友

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

确定