问题
I want to include a file based relative to my sandbox base directory inside of my m4 text without using the -I
switch.
So far, I have figured out how to grab the environment variables using a sys call:
define(MODEL_ROOT,`syscmd(`printf $MODEL_ROOT')')dnl
Next, I want to include a file based off that environment variable:
include(MODEL_ROOT/sw/lib/m4_macros/foreach2.m4)
In total, I have:
define(MODEL_ROOT,`syscmd(`printf $MODEL_ROOT')')
MODEL_ROOT
MODEL_ROOT/sw/lib/m4_macros/foreach2.m4
include(MODEL_ROOT/sw/lib/m4_macros/foreach2.m4)
Which prints:
/home/ross/sandbox
/home/ross/sandbox/sw/lib/m4_macros/foreach2.m4
/home/ross/sandboxforeach_example.m4:7: m4: Cannot open /sw/lib/m4_macros/foreach2.m4: No such file or directory
I know that the normal syntax for includes is
include(`file.m4')
But if I quote MODEL_ROOT/sw/lib/m4_macros/foreach2.m4
, then m4 like:
[...]
include(`MODEL_ROOT/sw/lib/m4_macros/foreach2.m4')
m4 complains:
[...]
foreach_example.m4:7: m4: Cannot open MODEL_ROOT/sw/lib/m4_macros/foreach2.m4: No such file or directory
How does one include a file with an environment variable in its path?
回答1:
I think you need to use esyscmd
instead of syscmd
. esyscmd
reads command line output.
回答2:
As the other answer mentions, you have to use the GNU extension esyscmd
to be able to retrieve the output of the command. The syscmd
macro just prints directly to stdout, ignoring all macros and divert
s.
That is why it looked like MODEL_ROOT
was working everywhere else: it was, but only in very simple situations where m4 didn't need to deal with its output.
However, regarding quoting:
include(MODEL_ROOT/sw/lib/m4_macros/foreach2.m4)
include(`MODEL_ROOT/sw/lib/m4_macros/foreach2.m4')
This should have the quotes moved:
include(MODEL_ROOT`/sw/lib/m4_macros/foreach2.m4')
The quotes prevent expansion of the MODEL_ROOT
macro, so they must not enclose it here (where you want it to be expanded). It is "proper" to quote the rest of the string, because it's not something you will want to be expanded by macros.
As an aside, a more robust way to get an environment variable from the shell would be something like:
define(`HOME', esyscmd(`printf \`\`%s\'\' "$HOME"'))
That will avoid problems caused by macro names, percentage signs, backslashes, glob characters, or whitespace in the environment variable's value. The only differences between this and your solution are the addition of \`\`%s\'\'
and quotes around the variable.
A caveat: esyscmd
will always have its output expanded as a macro, so it can be difficult to keep it truly sanitized. Even though I'm using quote symbols above, it will still trip up if those quote symbols exist in the environment variable.
来源:https://stackoverflow.com/questions/5346119/in-m4-how-do-you-include-a-file-that-has-an-environment-variable-in-its-name