英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论