2006年07月09日(日)
■[emacs][shell] emacsをバッチモードで使う
● 問題
僕の環境では nkf での文字コード変換がイマイチの品質で、信頼できない。
emacs の set-buffer-file-coding-system 関数は確実に動作するので、鶏に牛刀の感もあるが、emacs のバッチモードを使ってみることにする。
● とりあえず書いてみた。
当面の目的である、コード変換の処理は次のようになる。
for f in *.ixl; do emacs -batch \ -eval "(un-define-debian)" \ -eval '(set-language-environment "Japanese")' \ -visit $f \ -eval "(set-buffer-file-coding-system 'utf-8-unix)" \ -eval "(save-buffer-as-coding-system 'utf-8-unix t)" ; done ;
●無意味な繰替えしの回避
これで一応動くんだけれど、繰返しで毎回 emacs を起動して言語環境初期設定するのはバカみたい。
という訳で、無駄な動作を回避する版を作ってみる。
tmp=/tmp/${PPID}_${LINENO}.el ; \
echo "(un-define-debian)" > $tmp ; \
echo '(set-language-environment "Japanese")' >> $tmp ; \
for f in *.ixl ; \
do echo "(find-file\""${f}"\")" >> $tmp ; \
echo "(set-buffer-file-coding-system 'utf-8-unix)" >> $tmp ; \
echo "(save-buffer-as-coding-system 'utf-8-unix)" >> $tmp ; \
echo "(kill-buffer (current-buffer))" >> $tmp ; \
done ; \
emacs -batch -l $tmp
なんかちょっと不細工にも程がある、というコードだな。
こーいうのは書いていても全く楽しくない。
本当はヒアドキュメントを使いたかったんだけれど、対話的にヒアドキュメントを使うと EOF で入力待ちが終ってしまうので、ヒアドキュメントにダイナミックに追記していく、という使い方が出来ない。(※これは僕の誤解であった、小江戸らぐMLで聞いてきて、高橋さんにそれで無問題である)と教えてもらった。
●ヒアドキュメントを使ってみた
utf8-via-emacs () {
tmp=/tmp/${PPID}_${LINENO}.el
cat > $tmp <<- EOF
(un-define-debian)
(set-language-environment "Japanese")
EOF
for f in $*
do cat >> $tmp <<- EOF-Delta
(find-file "${f}")
(set-buffer-file-coding-system 'utf-8-unix)
(save-buffer-as-coding-system 'utf-8-unix 64)
(kill-buffer (current-buffer))
EOF-Delta
done
emacs -batch -l $tmp
rm $tmp ; }
●Gnuclient を使ってみた
ここまで作ってきたもので、何が具合が悪いか、というと、emacs を立ち上げるのに時間が掛るのが困る。どうせ emacs なんて常に動かしているんだから、動いている emacs プロセスを使ってやればいいじゃん、とふと思いつき、gnuclient の man を眺めると、ちゃんと -batch オプションがあるじゃん。
という訳で、emacs が動いている時は、gnuclient を使うようにした版も書いてみた。
↑にくらべるとリーダビリティは大部悪いんだが、劇的に早く動くようになった、やっと満足。
utf8-via-emacs () {
tmp=/tmp/${PPID}_${LINENO}.el
if [ `ps --no-headers -C emacs | wc -l` -gt 0 ]
then # emacs が動いていたら gnuclient を使う
EMACS=gnuclient
# カレントバッファの退避処理 括弧を閉じるのに注意
cat > $tmp << EOF
(save-current-buffer
EOF
else
EMACS=emacs # そーでなかったら、emacs をバッチモードで使う
# この場合日本語初期設定をしないといけない
cat > $tmp << EOF
; 日本語初期設定
(un-define-debian)
(set-language-environment "Japanese")
EOF
fi
for f in $*
do ff=`pwd`/$f
cat >> $tmp << EOF-Delta
(let ((cb (find-file "${ff}")))
(set-buffer-file-coding-system 'utf-8-unix)
(save-buffer-as-coding-system 'utf-8-unix 64)
(kill-buffer cb))
EOF-Delta
done
# gnuclient を使う場合、save-current-buffer マクロの括弧を閉じる
if [ gnuclient = $EMACS ] ; then cat >> $tmp << EOF-end
)
EOF-end
fi
$EMACS -batch -l $tmp
rm $tmp ; }
● 感想
非常に簡単なものではあるが、ダイナミックにコードを生成するプログラムになってしまった。
シェルでこういうことをするのは始めてだけれど、ヒアドキュメントを使えばとってもきれいに書けることが判った。ちょっと感動。
ところで、emacs はバッチモードとインタラクティブな動作とでは微妙に動きが違う。
例えば、上の例では、save-buffer でセーブしたら、コーディングシステムはもとのままで変らない。
● シェルスクリプト覚書
僕は対話モードのシェルの動作を誤解していて、入力プロンプトが出現する度に、あたらしいサブプロセスが生成され、個々のプロンプトは兄弟なプロセスである、と誤解していた。
$ LANG=C man
でもそれは、man を実行する時に、サブプロセスが生成されるからであって、プロンプト自体は、(特にshell や仮想ターミナルを明示的に起動しないかぎり、コンソールが起動されたときに起動されるシェルが一貫して出している筈である。
だからつまり、前のプロンプトで設定したシェル変数は、そのシェルの後のプロンプトから入力するコマンドで参照したり書換えたりすることが出来る。
こうやって書くとあたり前のことみたいだが、それを僕は誤解していた。
で、何がいいたいかというと、ヒアドキュメントのデリミッタの後の改行をエスケープすることは出来ないんだけれど、対話モードでヒアドキュメントを使っている時に、そこで改行しちゃって、新しい入力プロンプトから始めても実行上何の不都合もない、ということ。
つまりまとめると↓のようになる。
[Q] 対話的にシェルを使っていると、ヒアドキュメント の後の改行をエスケープ できません [A] そこはエスケープしなくっても無問題です。 プロンプトから引き続き普通にコマンドを入力して続ければいいでしょう。 何が問題ですか?
購入: 1人 クリック: 49回
- 23 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rls=GGLG,GGLG:2006-12,GGLG:ja&q=姜桂順
- 15 http://www.google.co.jp/search?sourceid=navclient-ff&ie=UTF-8&rls=GGGL,GGGL:2006-23,GGGL:ja&q=keyconfig+firefox
- 13 http://www.google.co.jp/search?q=emacs+バッチモード+environment&hl=ja&lr=lang_ja&client=firefox&rls=org.mozilla:ja:official&hs=IHB&start=10&sa=N
- 12 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:en-US:unofficial&hs=rMy&q="emacs+--batch"&btnG=検索&lr=
- 11 http://www.google.co.jp/search?q=emacs+batch&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a
- 9 http://www.google.co.jp/search?hl=ja&q=emacs+バッチ&btnG=検索&lr=
- 9 http://www.google.co.jp/search?q=ヒアドキュメント シェル&hl=ja&lr=&newwindow=1&start=10&sa=N
- 7 http://209.85.175.104/search?q=cache:rEFjirhWdxcJ:d.hatena.ne.jp/amt/20060709/BatchMode+ヒアドキュメント+待ち&hl=ja&ct=clnk&cd=1&gl=jp&client=firefox-a
- 7 http://d.hatena.ne.jp/keyword/iSilo
- 6 http://www.google.co.jp/search?hl=ja&q=シェル+入力プロンプト&lr=



