In m4, how do you include a file that has an environment variable in its name?

强颜欢笑 提交于 2019-12-12 16:19:46

问题


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 diverts.

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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!