我可以从 LaTeX 访问系统/环境变量吗?例如 $HOME

我可以从 LaTeX 访问系统/环境变量吗?例如 $HOME

例如,我想包含一个图形:~/figures/figure.pdf。在我的 Linux 机器上,这是/home/me/figures/figure.pdf,但在 OS X 上是/Users/me/figures/figure.pdf。如果有一个环境变量,我希望它能这样$HOME,以便 latex 文件可以在两台机器上编译\includegraphics{$HOME/figures/figure.pdf}。(当然它不会使用符号$)。

我刚刚发现这个帖子但是 write18 是最原生的方式吗?而且,在给定的例子中,赋值实际上不会在 LaTex 中定义变量。我试过了

\immediate\write18{echo "\newcommand{\HOME}{$HOME}" > var.tex}

但给了我这个错误:

! Argument of \@gobble has an extra }.

所以现在我很茫然。

答案1

如果您有最新的 TeX Live(2010 或更高版本)或 MiKTeX(v. 2.9),那么以下操作可以起作用(并且不需要-shell-escape命令行选项):

\usepackage{catchfile}
\newcommand{\getenv}[2][]{%
  \CatchFileEdef{\temp}{"|kpsewhich --var-value #2"}{\endlinechar=-1}%
  \if\relax\detokenize{#1}\relax\temp\else\let#1\temp\fi}

\getenv[\HOME]{HOME}

如果您只说,\getenv{VAR}那么变量的值就会被打印出来,而不是存储在控制序列中。

不仅HOME可以使用,还可以使用任何环境变量以及 TeXkpathsea系统中定义的“伪变量”,例如TEXMFTEXINPUTS

请注意,这是有效的仅有的使用pdflatex。使用其他引擎或较旧的发行版,需要 shell escape。当然 LuaTeX 有其与系统交互的方法。


适用于所有最近的引擎是

\documentclass{article}

\usepackage{ifxetex,ifluatex}

\ifxetex
  \usepackage{catchfile}
  \newcommand\getenv[2][]{%
    \immediate\write18{kpsewhich --var-value #2 > \jobname.tmp}%
    \CatchFileDef{\temp}{\jobname.tmp}{\endlinechar=-1}%
    \if\relax\detokenize{#1}\relax\temp\else\let#1\temp\fi}
\else
  \ifluatex
    \newcommand\getenv[2][]{%
      \edef\temp{\directlua{tex.sprint(
        kpse.var_value("\luatexluaescapestring{#2}") or "" ) }}%
      \if\relax\detokenize{#1}\relax\temp\else\let#1\temp\fi}
  \else
    \usepackage{catchfile}
    \newcommand{\getenv}[2][]{%
      \CatchFileEdef{\temp}{"|kpsewhich --var-value #2"}{\endlinechar=-1}%
      \if\relax\detokenize{#1}\relax\temp\else\let#1\temp\fi}
  \fi
\fi

\begin{document}
\getenv[\HOME]{HOME}\show\HOME
\end{document}

xetex在辅助文件\jobname.tmp被写入的情况下并且-shell-escape是必要的。

注意:LuaTeX 方法由 Patrick Gundlach 建议。如果变量未设置或未知kpathsea,则结果将为空字符串。


2019 年更新

使用最新版的 TeX 发行版,以下内容适用于所有引擎(当然,Knuth TeX 除外):、 、 和pdflatexxelatex无需lualatex无限制的 shell 转义。platexuplatex

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\getenv}{om}
 {
  \sys_get_shell:nnN { kpsewhich ~ --var-value ~ #2 } { } \l_tmpa_tl
  \tl_trim_spaces:N \l_tmpa_tl
  \IfNoValueTF { #1 }
   {
    \tl_use:N \l_tmpa_tl
   }
   {
    \tl_set_eq:NN #1 \l_tmpa_tl
   }
 }

\ExplSyntaxOff

\begin{document}

\getenv[\HOME]{HOME}\show\HOME

\end{document}

答案2

@egreg 已经回答了你的问题,所以我想我不会回答。建议不要依赖环境变量。如果 latex 文件只是\includegraphics{figures/figure.pdf}

然后,如果$HOME/figures//在 TEXINPUTS 环境变量或texmf.cnf配置设置中,则无需 LaTeX 明确访问机器特定信息即可找到该文件。这会将机器特定信息和目录结构保留在 kpathsearch 系统中,该系统经过优化以处理此类问题,而不是尽可能避免此类问题的宏层。

此外,对于主目录的特定情况,您可以(在至少 linux 和 windows/cygwin 上的 web2c 系统上,但我认为其他系统也是如此)使用\string~/figures/figure.pdfkpathsea 理解~的主目录(但您必须向其传递一个文字,~而不是不可破坏空间的正常活动定义,因此\string.

答案3

@egreg 针对新版本更新的答案对我来说不起作用,但是这样做:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\getenv}{om}
{
  \sys_get_shell:nnN{ kpsewhich ~ --var-value ~ #2 }{}#1
}

\ExplSyntaxOff

\begin{document}

\getenv[\HOME]{HOME}
\HOME

\end{document}

我不知道这是否是预期的行为,但它对我有用,并且根据文档,\sys_get_shell:nnN它似乎是预期的行为。

相关内容