端末の画面リセットが不便
日常使いのプラットフォームとして Ubuntu や FreeBSD を使っているのですが、Ubuntu の "端末" (gnome-terminal) では、man を見たり、テキストファイルを less で見たりしたあと終了するときに、man や less で表示していた中身がすっかり消えてしまい、man、less を起動するまえの状態にリセットされてしまいます。
直前まで見ていたテキストを参照しつつ次のコマンドを打ったりしたいのに、内容が消えてしまって困ります。
私の環境の場合、FreeBSD の MATEデスクトップの mate-terminal ではこのリセットは起きません。
でどういう場合にこうなるのか調査したところ、Ubuntu で 環境変数 TERM = xterm とか TERM = xterm-256color などにしている場合(ほかにもあると思いますが)に起きる症状とわかりました。
症状への対処方法(ユーザ毎、恒久的)
-
$ infocmp > tmpterm.ti
とやって、現在の端末制御情報をテキスト化します。 - 作成した tmpterm.ti をテキストエディタで編集して、その中の
rmcup=XXXX,とsmcup=YYYY,となっている部分だけを削除します。 -
$ tic -x tmpterm.ti
を実行すると $HOME/.terminfo/ ディレクトリの中に環境変数 TERM で設定している名前の端末のエントリが、一部削除後の情報を使って作成されます。
これで、端末のリセットは起こらなくなります。
症状への対処方法(利用者全体)
自分に限った対処ではなく、システム利用者全体に効果を及ぼしたければ、/etc/terminfo/ の下に書き換えたエントリを保存すればいいです。つまり、
$ sudo tic -x -o /etc/terminfo tmpterm.ti
で OK です。
何をやっているのか
多くの xterm 系端末には:
通常バッファ(Normal Screen Buffer)
代替バッファ(Alternate Screen Buffer)
の2種類があります。
通常バッファ → シェルの履歴が残る画面
代替バッファ → フルスクリーンアプリ専用の一時画面
で smcup は画面を代替バッファに切り替える機能、 rmcup は元のバッファに切り戻す機能の名前です。端末ソフト gnome-terminal はこの二つの機能を持っていて、よかれと思ってわざわざ切換えをしてくれているのでした。
上の対処方法では、このバッファ切換えの際にどのようなコマンド(エスケープシーケンス)を出力すればいいのかという情報を削除してしまい、端末に手出しをさせなくしているわけです。
恒久的な変更はしたくない場合
通常はバッファ切換えをしてくれていいのだが、切換えをやめてほしい場合がときどきあるという方もいるかと思います。
そんな方のためのコマンドのラッパーを考えてみました。
#!/bin/sh
#
# "noc" : not clear screen (www)
if [ $# -lt 1 ]; then
echo "noc command [arg ...]"; exit;
fi
# /tmp 配下に使い捨てのディレクトリを作成する
tmpdir=`mktemp -d`
# あとで使い捨てディレクトリの掃除をする
cleanup() {
rm -rf "$tmpdir"
}
trap cleanup EXIT INT TERM
# ターミナル情報のテキスト化
infocmp > "$tmpdir/myterm.ti"
# smcup と rmcup のエントリを削除する
sed -E -i 's/smcup=[^,]*,//g; s/rmcup=[^,]*,//g' "$tmpdir/myterm.ti"
# /tmp に修正したターミナル情報を保存
tic -x -o "$tmpdir" "$tmpdir/myterm.ti"
# /tmp のターミナル情報を使うよう環境変数をセット
export TERMINFO="$tmpdir"
# コマンド本体の実行
CMD=$1
shift
$CMD "$@"
# cleanup は trap EXIT でも呼ばれるが明示的にも呼ぶ
cleanup
# end
これを noc という名前で実行可能にし、 $HOME/bin に置いておき、使いたいときだけ呼び出します。
$ man entry
とする代わりに
$ noc man entry
とか、
$ less textfile
とする代わりに
$ noc less textfile
などとすると画面がリセットされません。
Cプログラムではどうすればよいか
私は、「vi や Vim ユーザーのためのバイナリエディタ」をC言語で作っているのですが、ここでも画面リセットは避けたいため、バイナリのコマンド内で infocmp や tic を起動して terminfo 情報を操作しています。
上記の noc でやっていることとほぼ同じ内容を、起動するコマンドの中で最初に実施しています。Linux と FreeBSD の両方で使える方法です。
ご興味のある方は下記をご覧ください。