结论:问题:未设置的环境变量的kpsewhich
输出\par
,我不知道如何剥离它。
我受到了这个问题的启发我可以从 LaTeX 访问系统/环境变量吗?例如 $HOME在发现kpsewhich
没有环境变量的情况下也可以工作后--shell-escape
,我尝试创建一个基于是否设置了给定环境变量的开关。然后我可以检查 eg 是否DARK
已设置并交换文本和背景颜色。
然而,问题出现了,即使未设置环境变量,也kpsewhich
似乎会输出换行符,这导致捕获的输出不为空。我已经尝试使用\tl_trim_spaces:N
(链接的答案中已经是这种情况)来剥离它,但无济于事。
是否有可能(a)指示kpsewhich
不要为未设置的环境变量打印换行符,(b)如果未设置变量,则读取失败的返回代码sys_get_shell:nnN
和kpsewhich
非零退出代码,或(c)剥离\par
变量的结果?
感谢@Phelype Oleinik,查看他的回答以获得解释,并查看@egreg 的回答以获得无需更改的解决方案\endlinechar
我现在可以使用以下代码实现我想要的功能:
\documentclass{article}
\usepackage{fontspec}
\usepackage{xparse}
\usepackage{xcolor}
\ExplSyntaxOn
\NewDocumentCommand{\ifenvset}{m m}
{
\sys_get_shell:nnN { kpsewhich ~ --var-value ~ #1 }
{ \int_set:Nn \tex_endlinechar:D { -1 } }
\l_tmpa_tl
\tl_if_empty:NTF { \l_tmpa_tl } {} { #2 }
}
\ExplSyntaxOff
\ifenvset{DARK}{
\pagecolor{black!90}
\color{white!90}
}
\begin{document}
\noindent
\verb|lualatex darkmode.tex|\\
\verb|env DARK=1 lualatex darkmode.tex|\\
\end{document}
答案1
当你执行 shell 命令时,TeX 会认为你已将命令的输出写入临时(伪)文件,然后读取该文件。读取该文件时,通常的规则适用:行尾转换为空格,空行转换为标记\par
。当命令的输出为空时,就好像文件有一个空行,然后将其转换为\par
。通常的技巧是将参数设置\endlinechar
为-1
,这样 TeX 就不会在行尾插入任何内容,也不会插入标记\par
。
中的第二个参数\sys_get_shell:nnN
是<setup>
,您可以在执行命令和读入伪文件之前更改这些类型的参数,因此您可以执行以下操作:
\sys_get_shell:nnN { kpsewhich ~ --var-value ~ #2 }
{ \int_set:Nn \tex_endlinechar:D { -1 } }
\l_septatrix_env_tl
将其放入 egreg 的\getenv
代码中:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\tl_new:N \l_septatrix_env_tl
\NewDocumentCommand \getenv { o m }
{
\sys_get_shell:nnN { kpsewhich ~ --var-value ~ #2 }
{ \int_set:Nn \tex_endlinechar:D { -1 } }
\l_septatrix_env_tl
\IfNoValueTF {#1}
{ \tl_use:N \l_septatrix_env_tl }
{ \tl_set_eq:NN #1 \l_septatrix_env_tl }
}
\ExplSyntaxOff
\begin{document}
\getenv[\HOME]{HOME}\show\HOME
\getenv[\HOMER]{HOMER}\show\HOMER
\end{document}
答案2
您可以定义\ifenvsetTF
(我认为这是一个更好的名称}
\tl_const:Nn \c_getenv_par_tl { \par }
\NewDocumentCommand{\ifenvsetTF}{mmm}
{
\sys_get_shell:nnN { kpsewhich ~ --var-value ~ #1 } { } \l_tmpa_tl
\tl_if_eq:NNTF \l_tmpa_tl \c_getenv_par_tl { #3 } { #2 }
}
完整示例:
\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
}
}
\tl_const:Nn \c_getenv_par_tl { \par }
\NewDocumentCommand{\ifenvsetTF}{mmm}
{
\sys_get_shell:nnN { kpsewhich ~ --var-value ~ #1 } { } \l_tmpa_tl
\tl_if_eq:NNTF \l_tmpa_tl \c_getenv_par_tl { #3 } { #2 }
}
\ExplSyntaxOff
\begin{document}
\getenv{LC_CTYPE}
\ifenvsetTF{LC_CTYPE}{SET}{UNSET}
\ifenvsetTF{BOZO}{SET}{UNSET}
\end{document}
但是,请注意,设置为空值的变量无论如何都会触发“取消设置”(使用此方法以及该\endlinechar
方法)。
如何定义expl3
条件?
\prg_new_protected_conditional:Nnn \septatrix_if_setenv:n {T,F,TF}
{
\sys_get_shell:nnN { kpsewhich ~ --var-value ~ #1 } { } \l_tmpa_tl
\tl_if_eq:NNTF \l_tmpa_tl \c_getenv_par_tl
{ \prg_return_false: }
{ \prg_return_true: }
}
完整代码
\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
}
}
\tl_const:Nn \c_getenv_par_tl { \par }
\prg_new_protected_conditional:Nnn \septatrix_if_setenv:n {T,F,TF}
{
\sys_get_shell:nnN { kpsewhich ~ --var-value ~ #1 } { } \l_tmpa_tl
\tl_if_eq:NNTF \l_tmpa_tl \c_getenv_par_tl
{ \prg_return_false: }
{ \prg_return_true: }
}
\NewDocumentCommand{\ifenvsetTF}{mmm}
{
\septatrix_if_setenv:nTF { #1 } { #2 } { #3 }
}
\ExplSyntaxOff
\begin{document}
\getenv{LC_CTYPE}
\ifenvsetTF{LC_CTYPE}{SET}{UNSET}
\ifenvsetTF{BOZO}{SET}{UNSET}
\end{document}