TeX Alchemist Online

TeX のこと,フォントのこと,Mac のこと

Luaで外部コマンドの標準出力を取り込むときの注意点

前記事のちょとした補足です。

doratex.hatenablog.jp

\begin{luacode*}
function readFromPipe(cmd)
  local f = assert(io.popen(cmd, 'r'))
  local s = assert(f:read('*a'))
  f:close()
  return s
end
\end{luacode*}

とした場合,コマンド出力結果の最後に改行があると,それを空白として文字列 s に取り込んでしまします。すると,それを tex.print() で出力したときにも,スペーストークンが入ってきてしまうことになります。

【実例】

%#!lualatex -shell-escape
\documentclass{jlreq}
\usepackage{luacode}

\begin{luacode*}
function readFromPipe(cmd)
  local f = assert(io.popen(cmd, 'r'))
  local s = assert(f:read('*a'))
  f:close()
  return s
end
\end{luacode*}

\newcommand\command[1]{\expandafter\detokenize\expandafter{\directlua{tex.print(readFromPipe('#1'))}}}

\begin{document}
\ttfamily
% uname コマンドの結果を出力してみる
[\command{uname -s}] [\command{uname -m}]
\end{document}

【結果】

確かに,右側に余分なスペースが入ってきてしまっています。 そこで,s に対してLuaの正規表現置換で末尾スペースを除去しようとして,こうしたとします。

【実例】

%#!lualatex -shell-escape
\documentclass{jlreq}
\usepackage{luacode}

\begin{luacode*}
function readFromPipe(cmd)
  local f = assert(io.popen(cmd, 'r'))
  local s = assert(f:read('*a'))
  f:close()
  return string.gsub(s, '%s+$', '')
end
\end{luacode*}

\newcommand\command[1]{\expandafter\detokenize\expandafter{\directlua{tex.print(readFromPipe('#1'))}}}

\begin{document}
\ttfamily
% uname コマンドの結果を出力してみる
[\command{uname -s}] [\command{uname -m}]
\end{document}

すると,今度は謎の1が出力に入ってきてしまいました。

【結果】

これは,gsub 関数は置換後の文字列と置換回数という2つの返値を返し,return でその両側が外側に伝えられてしまっているからです。

次のように,1つめの返値だけを受け取り,2つめの返値を捨ててしまえばOKです。

【実例】

%#!lualatex -shell-escape
\documentclass{jlreq}
\usepackage{luacode}

\begin{luacode*}
function readFromPipe(cmd)
  local f = assert(io.popen(cmd, 'r'))
  local s = assert(f:read('*a'))
  f:close()
  s = string.gsub(s, '%s+$', '')
  return s
end
\end{luacode*}

\newcommand\command[1]{\expandafter\detokenize\expandafter{\directlua{tex.print(readFromPipe('#1'))}}}

\begin{document}
\ttfamily
% uname コマンドの結果を出力してみる
[\command{uname -s}] [\command{uname -m}]
\end{document}

【結果】