While writing some Lua as a backend for my LuaTeX code I noticed the following. For background, here is the Lua code. This version is standard Lua. But you don't really need to understand Lua to understand what the function is doing.
I needed a function that would return both standard output and error to Lua, and hence to TeX.
Since Lua doesn't have a library function that does this, I had to roll one myself.
This version writes standard output to a file, and redirects standard error to standard output. Then it reads them both and returns them. This isn't particularly pretty, but better alternatives are not obvious.
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
Today, while in a state of momentary confusion, I wrote the following code as the argument command
to the function above.
"wkhtmltopdf searchpath(foo.html) foo.pdf"
In terms of the Lua function given above, this would be something like
exec_cmd("wkhtmltopdf searchpath(foo.html) foo.pdf", "STDOUT FROM WKHTMLTOPDF is %s", "STDERR FROM WKHTMLTOPDF IS %s")
So this command gets passed to the shell as:
wkhtmltopdf searchpath(foo.html) foo.pdf 2>&1 1> /tmp/lua_vyOiay
for some suitable temporary file e.g. /tmp/lua_vyOiay
.
This gives the error, if typed directly on the shell (and forgetting about the Lua, which has served its explanatory purpose)
bash: syntax error near unexpected token `('
But the interesting thing about this is that this error doesn't appear to go to standard output. At least, the above command does not collect it, and I wasn't able to collect it any other way.
So, in the interests of bullet-proofing my Lua function, here are my questions.
- What is going on above with that nonsense command, and why isn't the error being sent to stderr? This is just for my information.
- What can I do (if anything) to make sure that I collect the stderr string, and interrupt my TeX program as it should be interrupted?
After further discussion, 2 could be accomplished in at least 2 ways.
2a. Since it seems that the Bash shell itself it giving that error, I'd need a way to trap the standard error of the Bash shell itself, within Bash.
2b. A Lua approach of getting at the standard error of the shell, which here is spawned by Lua.
eval
would work, but it's also considered evil, unless you happening to be writing in Lisp or one of its relatives.eval
is frequently misused, and it's often the reputation from these misuses that gives it the label "evil". In its rightful place it's a powerful toolBut the interesting thing about this is that this error doesn't appear to go to standard output
: it goes, as you asked, to wherever 1 was pointing to originally, ie BEFORE you redirected 1 to the file (usually: 1 was outputing to the terminal, so stderr(2) goes there). if you want to collect both error and output in the same file to then send it to the user (and also do other things with it as you can re-read the file) :cmd... >the_file 2>&1
(which means: redirect stdout to the_file. now redirect stderr to wherever stdout currently is directed to, which is also the_file.).