HOME

文書に自分自身を処理するスクリプトを埋め込む

2016-3-31(Thu)

原稿自体に自分を処理するスクリプトを埋め込んでおこうという話。

原稿をテキスト書類で書くときに、長い言葉は自分流の略語を使って書いておき、それを後で sed 等で一気に置換するということがある。また、html を手書きするときに、はじめは表をタブ区切りで作っておいて、後でそれを html のタグに置き換えるということがある。LaTeX でも、マクロを書くよりもこうしたやり方のほうが簡単な場合がある。こうしたときにしばしば起こることは、後になって原稿を手直ししようと思ったときに、処理に使ったスクリプトが見つからないということである。ターミナルからワンライナーを使って変換したりしたときは、確実にこれが起こる。また、スクリプトにいくつものバージョンがあるとき、どれが正しいのかわからなくなる。そこで私は考えた。

原稿自身に自分を処理するスクリプトを埋め込んでおけばいいじゃないか! これならスクリプトを紛失したりしないし、他人に渡したときにも便利だろう。

sed スクリプト入り原稿と、それを処理するシェルスクリプト

方針としては、原稿から文書部分とスクリプト部分を切り分けて取り出し、文書部分にスクリプト部分を適用し、出力することにする。これなら、たいへん融通がきく。

原稿を処理するためのプログラムには何を使ってもいいわけだが、sh というのはあまりに危険だろう。できるなら他のプロセスを起動することがないようなプログラムが安心だ。そこで、gnu sed に --posix オプションをつけて使うことを考えた(gnu sed には、e コマンドというものがあり、スクリプトの中から別のプロセスを起動できる。これを避けるために --posix オプションを使うことができる)。

まず原稿ファイル中に sed のスクリプト部分を

<!--sed
ここにスクリプトを書く
sed-->

のように書いて、埋め込む。そして、この原稿ファイルに対して、

sh presed.sh input.html > output.html

のようにすると、所期のアウトプットが得られるようにしたい。この presed.sh スクリプトは、以下のようになる。

#!/bin/sh
source=$1
sed -ne '1 i\
/<!--sed/,/sed-->/d
/<!--sed/,/sed-->/{/<!--sed/d;/sed-->/d;p}' $source | 
sed --posix -f - $source 

これはシェルスクリプトではあるが、実際に起動しているのは sed に過ぎない。一つ目のプロセスでスクリプト部分を抽出し、二つ目のプロセスでそれをファイルに対して適用している。なお、出力時にはソースファイルに埋め込まれたスクリプト部分が削除されるようにしてある。

もちろん、こんなスクリプトを使わなくても、手動で処理できるのはもちろんである。

簡単な例

いくつか簡単な例を作ってみる。

文字列の置換

たとえば、ā を打ち込むのが面倒な環境では、次のようなファイルを用意する。コメント部分が sed のスクリプトである。

<!--sed
s/a-/ā/g
s/o-/ō/g
sed-->

amo- ama-s amat ama-mus ama-tis amant

これは、「amō amās amat amāmus amātis amant」のようになる。

また、タブ区切りの表から html の表を作りたいなら、次のようなソースファイルを用意する。

<!--sed
/<table>/,/<\/table>/{
/	/s/^/<tr><td>/
/	/s/$/<\/td><\/tr>/
/	/s/	/<\/td><td>/g
}
sed-->

<table>
	a	b	c
A	1	2	3
B	4	5	6
C	7	8	9
</table>

これは、

abc
A123
B456
C789

のような具合になる。おそらく、このやり方が効果を持つのは、もっと大きな表のときだろう。

(なお、colspan や rowspan を使うような表を作り場合は、awk で処理したほうがいいだろうと思う。たとえば、「awk で複雑な表の html を作成するメモ」)

ルビ

html をエディタで手書きするとき、ふりがなをつけるのは、なかなか面倒である。

<!--sed
:a
s/{\([^あ-ん][^あ-ん]*\)\([あ-ん][あ-ん]*\)\([^{]*\)}/<ruby>\1<rt>\2<\/rt><\/ruby>{\3}/
t a
s/{}//g
s/<\/ruby><ruby>//g
sed-->

{海驢あしか}と{漢かん字じ}で{書か}く

というかんじ。

これは、「海驢あしかかんく」みたいな様子になる。

おわり