Access variable declared inside Makefile command

2019-03-04 04:42发布

I'm trying to access a variable declared by previous command (inside a Makefile).

Here's the Makefile:

all:
  ./script1.sh
  ./script2.sh

Here's the script declaring the variable I want to access,script1.sh:

#!/usr/bin/env bash
myVar=1234

Here's the script trying to access the variable previously defined, script2.sh:

#!/usr/bin/env bash
echo $myVar

Unfortunately when I run make, myVar isn't accessible. Is there an other way around? Thanks.

2条回答
劫难
2楼-- · 2019-03-04 05:28

The two separate invocations of the scripts create two separate environments. The first script sets a variable in its environment and exits (the environment is lost). The second script does not have that variable in its environment, so it outputs an empty string.

You can not have environment variables pass between environments other than between the environments of a parent shell to its child shell (not the other way around). The variables passed over into the child shell are only those that the parent shell has export-ed. So, if the first script invoked the second script, the value would be outputted (if it was export-ed in the first script).

In a shell, you would source the first file to set the variables therein in the current environment (and then export them!). However, in Makefiles it's a bit trickier since there's no convenient source command.

Instead you may want to read this StackOverflow question.

EDIT in light of @ghoti's answer: @ghoti has a good solution, but I'll leave my answer in here as it explains a bit more verbosely about environment variables and what we can do and not do with them with regards to passing them between environments.

查看更多
Summer. ? 凉城
3楼-- · 2019-03-04 05:29

Make will run each shell command in its own shell. And when the shell exits, its environment is lost.

If you want variables from one script to be available in the next, there are constructs which will do this. For example:

all:
    ( . ./script1.sh; ./script2.sh )

This causes Make to launch a single shell to handle both scripts.

Note also that you will need to export the variable in order for it to be visible in the second script; unexported variables are available only to the local script, and not to subshells that it launches.


UPDATE (per Kusalananda's comment):

If you want your shell commands to populate MAKE variables instead of merely environment variables, you may have options that depend on the version of Make that you are running. For example, in BSD make and GNU make, you can use "variable assignment modifiers" including (from the BSD make man page):

 !=      Expand the value and pass it to the shell for execution and
         assign the result to the variable.  Any newlines in the result
         are replaced with spaces.

Thus, with BSD make and GNU make, you could do this:

$ cat Makefile

foo!=   . ./script1.sh; ./script2.sh

all:
    @echo "foo=${foo}"

$
$ cat script1.sh
export test=bar
$
$ cat script2.sh
#!/usr/bin/env bash

echo "$test"
$
$ make
foo=bar
$

Note that script1.sh does not include any shebang because it's being sourced, and is therefore running in the calling shell, whatever that is. That makes the shebang line merely a comment. If you're on a system where the default shell is POSIX but not bash (like Ubuntu, Solaris, FreeBSD, etc), this should still work because POSIX shells should all understand the concept of exporting variables.

查看更多
登录 后发表回答