使用 shell escape 来访问系统时间

使用 shell escape 来访问系统时间

先前的问题,我要求\pdfelapsedtime在 XeTeX 和 LuaTeX 中提供(测量自当前运行开始以来的时间)的类似物。提供了一个 LuaTeX 解决方案,现在已成为 Heikopdftexcmds软件包的一部分。但是,没有提供 XeTeX 解决方案。我能看到的唯一在 XeTeX 中测量时间的方法是使用 shell-escape。

使用 Unix 系统上的 pdfTeX,我将构建一个包装器

\everyeof{\noexpand}
\catcode`\%=12
\message{\input|"date +%s.%N"}

(用 编译pdftex --shell-escape)。

  1. 是否有与 XeTeX 类似的\input|...构造?(写这个问题的时候我认为这个构造可行。)

  2. 在各种操作系统中如何访问系统时间?

答案1

管道支架

pdfTeX自版本 1.40.0(2007-01-01 发布)起支持管道。来自NEWS

shell 转义:如果文件名的第一个字符\openin\openout \input管道符号 ( |),则假定该文件名是对文件名其余部分中给出的命令行的管道请求

根据 TeX 发行版的不同,该功能的启用方式也不同:

  • TeX Live:--shell-restricted(默认)允许调用一些命令(例如 kpsewhich、makeindex。请参阅shell_escape_commands中的变量texmf.cnf。否则需要完整的 shell 转义权限。它们可以通过选项“--shell-escape”进行设置。
  • MiKTeX:管道支持通过“--enable-pipes”激活。 Shell 转义选项不影响管道。

软件包catchfile(用于纯文本和 LaTeX 格式)将在 2012/07/30 v1.6 版本中添加\CatchPipeDef\CatchPipeEdef支持 pdfTeX 的管道功能。

LuaTeX不具备与 pdfTeX 相同的管道功能,因为它具有io.popen可用于此目的的 Lua 函数。Pacakgepdftexcmds提供\pdf@pipe包装器以方便使用。

特克斯:我无法在 TL2011/Linux 或 MiKTeX 2.9 中运行和工作管道。在后一种情况下,我只能捕获一个空行,而不是预期的程序输出。

独立于操作系统的命令行

如今 TeX 发行版通常将 LuaTeX 包含在其程序中texlua。例如,以下 Lua 脚本打印自 1970-01-01 以来的时间(以秒为单位):

if os.gettimeofday then
  print(os.gettimeofday())
else
  print(os.date("%s"))
end

然后命令调用

texlua gettimeofday.lua

1343650327.0485例如,打印。

但是如果 gettimeofday.lua 不在当前目录中,texlua则无法找到它,因为其kpathsea模块未处于活动状态。至少 TL 和 MiKTeX 提供了 kpsewhich查找文件的功能。

pdfTeX 和新版本 (2012/07/30 v1.6) 包的示例catchfile

\CatchPipeEdef\ScriptGettimeofday{kpsewhich gettimeofday.lua}{\endlinechar=-1}
\CatchPipeEef\CurrentTime{texlua \ScriptGettimeofday}{\endlinechar=-1}

\CurrentTime包含结果。或者使用低级命令(使用 e-TeX),它类似于:

\begingroup
  \everyeof{\noexpand}%
  \endlinechar=-1 %
  \edef\file{\input |"kpsewhich gettimeofday.lua"}
  \xdef\CurrentTime{\input |"texlua \file"}
  % Use \@@input in LaTeX instead of the redefined \input
\endgroup

PS: 新版本软件包catchfilecatchfile-1.6.pdf
(该.dtx文件附加在 PDF 中。继续运行texcatchfile.dtx解压包。)

回答 Bruno 的评论:

如果没有管道,则可以使用普通的 write18 功能。但是有很多缺点:

  • 较慢(文件写入、搜索和读取)
  • 可能会找到错误的文件。可以通过使用进程在文件中写入一些随机字节write18并读回这些字节并检查它们是否相同来进行测试。
  • 该解决方案无法扩展。
  • 更多可能中断的情况:文件未写入(例如只读目录)、无法找到、找到错误的文件等……
  • 需要唯一的临时文件名以避免在多用户系统或多个进程中同时发生冲突。
  • 清理:删除命令再次依赖于操作系统(rm在 Unix 中,del在 Windows 中)。或者临时文件保留。

答案2

一种方法是基于 Heiko Oberdiek 对这个问题的回答,以及egreg 对类似问题的回答是下面的代码。由于我不知道如何将参数传递给使用 解释的 lua 脚本,因此变得更加复杂,因此每次调用函数时,texlua我都会在 lua 文件中对参数进行硬编码。\blf@time@base

由于 XeTeX 中没有管道,因此禁止使用任何可扩展的解决方案,因此每次使用\pdf@setelapsedtime时间之前都应调用该函数。此解决方案具有 Heiko 的答案中指出的所有缺点。特别是,在我的系统上,每次执行都需要 0.1 秒,这相当慢。\pdf@elapsedtime\write18\test

\catcode`\@=11
\newwrite\blf@time@write
\newread \blf@time@read
\gdef\blf@time@base{0}%
\protected\gdef\blf@time@aux#1#2%
  {%
    \begingroup
      \escapechar=-1
      \immediate\openout\blf@time@write\jobname.lua%
      \immediate\write\blf@time@write
        {%
          os.remove("\jobname.timestamp")
          if os.gettimeofday then
            time = os.gettimeofday()
          else
            time = os.date("\string\%s")
          end
          val = .5 + 65536 * (time - \blf@time@base)
          if val > 2147483647 then
            val = 2147483647
          end
          io.output("\jobname.timestamp"):write(string.format("%
            \string\%f\string\\n\string\%d", time, val))
        }%
      \immediate\closeout\blf@time@write
      \immediate\write18{texlua \jobname.lua}%
      \endlinechar-1%
      \immediate\openin\blf@time@read\jobname.timestamp
      \readline\blf@time@read to \blf@time@tmp
      #1%
      \readline\blf@time@read to \blf@time@tmp
      #2%
      \immediate\closein\blf@time@read
    \endgroup
  }%
\protected\gdef\pdf@resettimer
  {\blf@time@aux{\xdef\blf@time@base{\blf@time@tmp}}{}}%
\protected\gdef\pdf@setelapsedtime
  {%
    \blf@time@aux{}%
      {\protected\xdef\pdf@elapsedtime{\numexpr\blf@time@tmp\relax}}%
  }%
\pdf@resettimer
\pdf@setelapsedtime


\def\test
  {%
    \pdf@setelapsedtime
    \message{\the\pdf@elapsedtime}%
  }
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\test\test\test\test\test\test\test\test\test\test
\bye

用 编译xetex --shell-escape <filename>.tex

相关内容