对于我的包和类的新版本,standalone
我喜欢调用外部程序:进一步(pdf)latex
运行以选择性地编译包含的standalone
文件,并将生成的 PDF 转换为 PNG(取决于上次运行创建的 PDF 至少在\begin{document}
第一页被刷新之前不会被覆盖)。
我当然知道这可以通过使用来完成\immediate\write18{<command> <arguments>}
,这需要将命令添加到shell_escape_commands
变量中texmf.cnf
并shell_escape
设置为p
,或者用户使用该-shell-escape
参数。
现在我喜欢在代码中测试调用是否write18
成功,即是否允许执行。我知道这\ifeof18
将返回错误的如果write18
特征是完全地已禁用(shell_escape = 0
在texmf.cnf
或当-no-shell-escape
使用参数时),但它返回真的如果受限制的 write18
模式已激活,这是默认模式。
有没有办法测试最后的 write18 调用是否被阻止?(我知道我可以手动测试该调用应生成的文件是否write18
已创建或更新。)
更新
文件中.log
为每个 write18 调用显示以下行之一,具体取决于此功能是否被禁用、启用或在限制模式下运行并且是否允许执行命令:
runsystem(<command>)...disabled.
runsystem(<command>)...executed.
runsystem(<command>)...executed safely (allowed).
runsystem(<command>)...disabled (restricted).
那么,如何才能在 LaTeX 文件中获取这些信息(无需实际读取文件.log
)?
答案1
似乎除了和之外,pdflatex
没有提供任何其他状态变量。这在\ifeof18
\pgfshellescape
中远海运Heiko Oberdiek 撰写。他还建议为 pdfTeX(和/或其他 TeX 引擎)打开功能请求,我就是这么做的。
以下是我想到的解决方案:
正如两个答案中提到的,检查的一个好方法write18
是\pdfshellescape
宏,自 pdftex 1.30.0 起可用。如果\write18
启用,则为 1,如果受限,则为 2,否则为 0。它在 XeTeX 或 LuaTeX 中不可用。但是,Heiko Oberdiek 的软件包pdftexcmds
将其添加到 LuaTeX 中,还会为您检查 pdfTeX >=1.30.0。然后以 的形式提供宏\pdf@shellescape
。
在我的例子中,我想检查转换命令是否成功。我想使用\pdffilemoddate
(\pdf@filemoddate
与pdftexcmds
)来检查要生成的文件是否更新。结合\IfFileExists
这一点可以进行非常合理的测试,该测试适用于 pdfLaTeX 和 LuaLaTeX。对于 XeLaTeX,只能实施非常有限的测试。
以下宏等待输出文件的名称和命令:
\writesuccess{<output file>}{<command line>}{<success>}{<failure>}
但是,如果调用的命令执行失败,并在过程中更新文件修改日期,则宏会将其报告为成功。目前没有办法检查这一点。
完整代码及示例:将生成的 PDF 转换为 PNG,需要运行两次,其中至少第二次需要-shell-escape
:
\documentclass{standalone}
% Use `pdftexcmds` to support LuaTeX and take advantage of
% the included checks like version of pdflatex, existence of \ifeof18, etc.:
\usepackage{pdftexcmds}
\makeatletter
\ifx\pdf@filemoddate\@undefined
% Without filemoddate (e.g. XeLaTeX) only the existence of the file can be tested:
\newcommand{\writesuccess}[2]{%
\immediate\write18{#2}%
\IfFileExists{#1}%
}
\else
% Real version:
% Check if to-be-generated file exists afterwards and is newer:
\newcommand{\writesuccess}[2]{%
\begingroup
\edef\filemodbefore{\pdf@filemoddate{#1}}%
\immediate\write18{#2}%
\IfFileExists{#1}{%
\edef\filemodafter{\pdf@filemoddate{#1}}%
\ifx\filemodbefore\filemodafter
\let\next\@secondoftwo
\else
\let\next\@firstoftwo
\fi
}{%
\let\next\@secondoftwo
}%
\expandafter
\endgroup
\next
}
\fi
\makeatother
\writesuccess{\jobname.png}{convert -density 600 \jobname.pdf \jobname.png}{%
\message{^^JYes^^J}%
}{%
\message{^^JNo^^J}%
}
\begin{document}
Test
\end{document}
答案2
为了解决同样的任务,我使用了
\ifnum\pdfshellescape=1
% Yes, enabled
\else
% No, disabled
\fi
控制序列\pdfshellescape
(仅?)在 中可用pdftex
,即您还需要检查它是否存在。
答案3
该bashful
包可能对您的目的有用。它确实管理\write18
错误,尽管我不确定它是否完全按照您要求的方式。这是一个小演示:
\documentclass[a6paper]{article}
\usepackage[verbose]{bashful}
\usepackage{graphicx}
\begin{document}
Here I create a small \LaTeX{} file:
\bash[script]
cat > delme.tex << EOF
\documentclass{standalone}
\begin{document}
Lorem ipsum dolor sit amet!
\end{document}
EOF
\END
Now I shall run the file I just created through \LaTeX{},
\bash[script]
pdflatex -shell-escape delme.tex
\END
obtaining the following output
\begin{center}
\fbox{\includegraphics{delme.pdf}}
\end{center}
\end{document}
生成以下输出:
答案4
您可以实现\ifwritexviii
条件。这直接取自泽佩斯安(这也是从 Heiko 的一个包裹中截取的):
\def\xepersian@cmds@temp#1{%
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname xepersian@#1\endcsname\relax
\begingroup
\escapechar=-1 %
\edef\x{\expandafter\meaning\csname#1\endcsname}%
\def\y{#1}%
\def\z##1->{}%
\edef\y{\expandafter\z\meaning\y}%
\expandafter\endgroup
\ifx\x\y
\expandafter\def\csname xepersian@#1\expandafter\endcsname
\expandafter{%
\csname#1\endcsname
}%
\fi
\fi
}%
\xepersian@cmds@temp{shellescape}
\newif\ifwritexviii
\ifnum\xepersian@shellescape=1\relax
\writexviiitrue
\else
\writexviiifalse
\fi
你可以使用它作为:
\ifwritexviii
% material if shell scape is enabled
\else
% material if shell escape is disabled
\fi