让 Bash 将此错误发送到 std error

让 Bash 将此错误发送到 std error

在为我的 LuaTeX 代码编写一些 Lua 作为后端时,我注意到以下内容。作为背景,这里是 Lua 代码。这个版本是标准Lua。但你并不需要真正了解 Lua 才能理解该函数在做什么。

我需要一个函数,它可以将标准输出和错误返回给 Lua,从而返回给 TeX。

由于 Lua 没有执行此操作的库函数,因此我必须自己编写一个。

此版本将标准输出写入文件,并将标准错误重定向到标准输出。然后它读取它们并返回它们。这不是特别漂亮,但更好的替代方案并不明显。

local function exec_cmd(command, stdout_message, stderr_message)
   local filename=os.tmpname()
   local cmd = string.format(command .. " 2>&1 1> %s", filename)
   local pipe = io.popen(cmd)
   local stderr = pipe:read("*all")
   pipe:close()
   local f = assert(io.open(filename, "r"))
   local stdout = f:read("*all")
   f:close()
   os.remove (filename)
   if stdout ~= nil and stdout ~= '' then
      print(string.format(stdout_message, stdout))
   end
   if stderr ~= nil and stderr ~= '' then
      error(string.format(stderr_message, stderr))
   end
end

今天,在一时的困惑中,我编写了以下代码作为command上面函数的参数。

"wkhtmltopdf searchpath(foo.html) foo.pdf"

就上面给出的 Lua 函数而言,这将类似于

exec_cmd("wkhtmltopdf searchpath(foo.html) foo.pdf", "STDOUT FROM WKHTMLTOPDF is %s", "STDERR FROM WKHTMLTOPDF IS %s")

所以这个命令被传递到 shell:

wkhtmltopdf searchpath(foo.html) foo.pdf 2>&1 1> /tmp/lua_vyOiay

对于一些合适的临时文件,例如/tmp/lua_vyOiay.

如果直接在 shell 上输入(并且忘记了 Lua,它已经达到了解释的目的),这会给出错误

bash:意外标记“(”附近出现语法错误

但有趣的是,这个错误似乎没有进入标准输出。至少,上面的命令没有收集它,而且我无法以任何其他方式收集它。

因此,为了保证我的 Lua 函数的安全,以下是我的问题。

  1. 上面那个无意义的命令发生了什么,为什么错误没有被发送到 stderr?这仅供我参考。
  2. 我可以做什么(如果有的话)来确保收集 stderr 字符串,并中断我的 TeX 程序,因为它应该被中断?

经过进一步讨论,2至少可以通过2种方式来完成。

2a.由于 Bash shell 本身似乎会给出该错误,因此我需要一种方法来捕获 Bash shell 本身的标准错误。

2b.获取 shell 标准错误的 Lua 方法,这里是由 Lua 生成的。

答案1

Lua程序基本上可以归结为运行

io.popen("syntax(error) 2>&1 1>outputfile"):read("*all")

其运行相当于

sh -c 'syntax(error) 2>&1 1>outputfile'

io.popen()捕获它启动的 shell 的标准输出,但不捕获标准错误。如果那里没有语法错误,重定向会将 stderr 安排到管道,将 stdout 安排到文件。但由于语法错误,shell 无法执行到那么远,因此不会处理重定向。 (外壳程序不明白您要告诉它做什么。)

要实际捕获 stdout 和 stderr,通常会在启动外部命令之前将两者连接到管道(或其他)。例如,Pythonsubprocess.Popen()stdoutstderr参数。但是Lua的标准库有点贫瘠,而且看起来并不是可以直接使用的。您必须编写一个 C 模块来提供该功能。

正如评论中提到的,将命令包装起来eval会有所帮助,因为生成的命令行将是

eval 'syntax(error)' 2>&1 1>outputfile

shell 会在运行之前处理重定向eval。但是,当然,您需要添加一组额外的转义来保护内部命令中可能有的任何单引号。

相关内容