* TeX における外部コマンドの実行 [#c035394f]

TeX(または LaTeX)におけるタイプセットでは,「TeX エンジン自身が持たない機能を外部コマンドの力を借りて補う」ということが時々行われます。
ここでは,そのような外部コマンドの実行についておおまかに説明します。

まずは(もっともよく知られている)画像挿入時の extractbb を例に説明し,それに続いて一般化した説明を加えます。
もし [[LaTeX入門/図表]] でつまずいてこの項目を訪れたならば,最初の2項目を読めば多くの場合解決するでしょう。

// LaTeX 入門からリンクすることを想定。
// 数年前(約5年前くらい?)の TeX 環境にも対応できるように詳しく。
// なお extractbb の自動実行より .xbb を事前に作っておく方が若干パフォーマンスが
// 上がるのも事実なので,そのようなポイントも含めて幅広く触れる。

#contents

** 実例 1 :画像の挿入と extractbb [#n3c795bf]

[[LaTeX入門/図表]]の後半で述べているとおり,DVI ファイルを経由して画像を取り込む場合,それは TeX 自身ではなく,“DVI ファイルの中に書き込まれた画像の取り扱いに関する指示”を [[dvipdfmx]] などの DVI 処理ソフトウェアが解釈する,という仕組みになっています。
TeX が組版するうえで問題になるのは''その図表を版面(紙面)に配置するためにどれくらいの幅と高さを確保するか''だけで,そのために画像のサイズにあたる情報(いわゆるバウンディングボックス情報)を必要とします。

しかし,TeX 自身は EPS ファイル以外の画像から自前でバウンディングボックス情報を取得することができません((これは,pLaTeX や upLaTeX のように DVI ファイルを出力する LaTeX エンジンに広く当てはまります。なお PDF ファイルを直接出力する pdfLaTeX や LuaLaTeX などのエンジンは自分で画像を解釈し,自分にとって必要なバウンディングボックス情報を取得することができます。))。
そこで,外部コマンドの力を借りてバウンディングボックスを取得する仕組みを利用します。
以下,最近の TeX 環境(TeX Live 2015 以降あるいは W32TeX を想定)では知らなくてもよいことかもしれませんが,説明不足にならないように書いておきます。

LaTeX に続いて dvipdfmx で処理することが決まっている場合は,extractbb というコマンドによって画像のバウンディングボックスを取得します((実は extractbb というプログラムは dvipdfmx のシンボリックリンクです。すなわち extractbb は dvipdfmx それ自身(見た目の名前が違うだけ)です。))。
たとえば,apple.png という PNG 画像ファイルのバウンディングボックス情報は

 extractbb apple.png

によって取得でき,apple.xbb というテキストファイルに書き込まれます。

 %%Title: apple.png
 %%Creator: extractbb 20150315
 %%BoundingBox: 0 0 204 238
 %%HiResBoundingBox: 0.000000 0.000000 204.463098 238.060320
 %%CreationDate: Tue Sep 01 06:42:17 2015

さきほど EPS ファイルからは自前でバウンディングボックス情報を取得できると述べましたが,それは EPS ファイルの冒頭に %%BoundingBox: という行が既に存在するからです。
extractbb は PNG/JPG/PDF ファイルのバウンディングボックスをこのような書式で書き出すことができるため,TeX はこの .xbb ファイルを読み込んで画像のサイズを把握することができるのです。
extractbb は PNG/JPG/PDF ファイルのバウンディングボックスをこのような書式で書き出すことができるため,TeX はこの .xbb ファイルを読み込んで画像のサイズを把握することができるのです((TeX Live 2015 以降ではバウンディングボックス情報を .xbb ファイルに書き出すことなく,直接パイプ入力で TeX エンジンに渡すように変更されていますが,この場合も本質的には同じです。))。

** 外部コマンドの自動実行 (restricted shell escape) [#y8305f04]

いま extractbb を例に,外部コマンドが必要となる例を説明しました。
TeX によるタイプセットの前に人の手で extractbb を実行して .xbb ファイルを作っておけば,TeX はその .xbb ファイルを読み取ってくれるのですが,いちいち実行するのは面倒です。
そこで,TeX によるタイプセット中に必要に応じて外部コマンドを実行する仕組みがあります。

しかし,なんでもかんでも外部プログラムを TeX から実行できてしまうとするとそれは危険です。
[[TeX Live]] や [[W32TeX]] では標準で restricted shell escape という仕組みが有効になっています(([[LaTeX入門/最初の例]] で「吾輩は猫である」を pLaTeX で処理したときに restricted \write18 enabled. と表示されているのはこのことです。))。
これは,あらかじめ安全と認められるプログラムを一覧にしておき,それらだけ自動で TeX から呼び出せるようにするというものです。
これは,あらかじめ安全と認められるプログラムを一覧にしておき,それらだけ自動で TeX から呼び出せるようにするというものです。但し,restricted shell escape という
名前が示すように,コマンドラインの形式が単純なものに制限されています。
安全なプログラムの一覧は texmf.cnf というファイル((kpsewhich -all texmf.cnf というコマンドでファイルの場所を見つけることができます。複数存在する場合はすべての texmf.cnf が読み込まれますが,各キー(shell_escape_commands のように “=” で結ばれた式の左辺にあたる変数)に与えられた値(キーに対して “=” で結ばれた式の右辺)については “前に書かれているものほど” 優先します。多くの場合,この shell_escape_commands の値を記述した texmf.cnf は (略)/texlive/2015/texmf-dist/web2c/texmf.cnf に置かれていますが,それより優先される texmf.cnf の中に shell_escape_commands の値が指定されている場合はそちらが採用されます。))に書かれていて

-TeX Live 2015 の場合
 shell_escape_commands = \
 bibtex,bibtex8,\
 extractbb,\
 kpsewhich,\
 makeindex,\
 mpost,\
 repstopdf,\
-W32TeX の場合
 shell_escape_commands = \
 bibtex,pbibtex,jbibtex,repstopdf,epspdf,extractbb,\
 makeindex,mendex,mpost,pmpost,upmpost,kpsewhich

のようになっています(行末の \ は “エスケープ” つまりその後の改行文字を無視するという意味)。
ここに extractbb が書き込まれていれば,TeX が自動で extractbb を実行することができる状態です。
具体的には

-TeX Live 2015 以降(MacTeX-2015 以降も含む)
-W32TeX
-[[美文書第6版>http://oku.edu.mie-u.ac.jp/~okumura/bibun6/]]からインストールした TeX Live 2013

の場合が該当します(これ以外にも,[[TeX 入手法>TeX入手法]]を参考にしてインストールした場合は,TeX Live 2014 が最新だった当時は extractbb を書き加えるように指示していたと思います)。
もし extractbb が自動実行プログラムに含まれていない場合は,[[こちらのアーカイブ情報>古い情報#rf074b4b]]を参考にしてください。

** 任意の外部コマンドの実行とすべての外部コマンドの禁止 (-shell-escape, -no-shell-escape) [#d24dd610]

標準では restricted shell escape ですが,任意の外部プログラムを TeX から実行できるようにすることもできます。
それには LaTeX などの実行時に -shell-escape オプションを付けます。

 platex -shell-escape test.tex

逆に,すべての外部プログラムの実行を禁止したい場合は -no-shell-escape オプションを付けます。

 platex -no-shell-escape test.tex

** 実例 2 : [#p6141839]

% pbibtex とか mendex のような例も挙げられるとよいですね。