PR

FreeBSD ksh 設定

FreeBSD
記事内に広告が含まれています。

先週の日曜日は母の日ということで、久しぶりに私の母親とドライブに出かけてきました。もともとブラブラとドライブするのは好きなのですが、ドライブしようと思った日に、私の嫁さんがジムに行くのでダメ!と怒られたのと、偶然母の日であったこととから二人だけでのドライブとなりました。車を動かし始めてからどこに行くか考えている間に中国道に差し掛かり、しばらく走っていると徳島こちら。。。という文字に誘われるようにハンドルを左に切り、その勢いで淡路島を大きく一周ほぼ地道で走ってきました。最近玉ねぎが高いと例の友人が言っていたのを思い出し、道端で大袋入りの玉ねぎを買って帰ろうと思いましたが、思ったほど安くなかったので、なんならちょっと安めの自宅近所の八百屋とあまり変わらない値段だったので、結局お土産は淡路ビールの詰め合わせとなってしまいました 🙂

さて、以前にログインシェルを /bin/sh から /bin/ksh ( 実際は /usr/local/bin/ksh で、/usr/local/bin/ksh からのシンボリックリンク ) へ変更しました。今回は /bin/ksh をちょっと使いやすくしてみましょう。/bin/ksh に限らず、シェルをカスタマイズする場合に大きく2つのカスタマイズがあります。

環境変数

環境変数とはその変数を適切にセットすることで、アプリケーションの動作をコントロールする方法です。まず、デフォルトでどのような変数がセットされているか見てみましょう。FreeBSD へログインして set コマンドを実行してください。現在セットされている変数が表示されます。

デフォルトの環境変数

代表的な変数をいくつかご紹介します。

LANG

LANG 変数は表示されるメッセージの言語を変更することができる変数です。ロケールの設定ともいわれます。デフォルトでは C.UTF-8 にセットされています。これはシステム標準の言語、つまりアメリカ英語のメッセージが表示されるということを意味しています。日本語に関係するロケールは3種類あります。一覧が locale -a で見ることができるので日本語関係だけをピックアップしてみます。

LANG が eucJP と UTF-8 で見え方が同じですが、実は異なるコードを発生しています。が、Tera Term が EUC も UTF-8 も日本語であると判断して正しいフォントにマップしています。

EUC と UTF-8 の octal dump の結果。SJIS はロケールとしては存在するようですが、インプリメントはされていないようです。

その判断を行うのが Tera Term のこの部分です。

Tera Term の言語判定

この設定をいじってしまうと、正しく表示されなくなります。例えば、言語を UTF-8 にすると、

Tera Term のロケールを UTF-8 にしてみる。

そうすると、UTF-8 以外は理解しないようになります。

EUC は正しく理解されなくなりました。

ただ、他の言語も UTF-8 であれば正しく理解されます。あまり良い簡単な例がなかったのですが、中国語のメッセージがありました。

中国語のわかる方、あってます?

FreeBSD のマニュアルによりますと、個人個人で環境変数をセットしてゆく方法より、/etc/login.conf に default をベースにして、英語以外のクラスを作って、それを /etc/master.passwd で指定する方法が推奨されています。日本語の場合ですと、日本語クラスを作成して、cap_mkdb コマンドでデータベースファイルを作成する。

ログインクラス japanese を作成する。
データベースファイルを作成し、vipw で /etc/master.passwd ファイルを編集する。

vipw 中で class を指定する。

japanese クラスを自分のクラスとして指定する。
こんな感じです。

/etc/login.conf はデフォルトの設定なので、その設定は個々の設定で上書きされます。例えば、先ほどデフォルトを日本語に変えたのですが、個々の設定で中国語に変更できます。

個々の設定のほうが優先度が高いです。

/etc/login.conf に個別に作成して vipw で埋め込むアイデアを批判するわけではないのですが、後に M$ Active Directory でユーザ管理を行おうとすると、この class フィールドの取り扱いに困ります。ですので、FreeBSD ローカルでユーザ管理を行うのであれば各ユーザに class フィールドを指定するのが楽ちん、M$ Active Directory でユーザ管理を行うのであれば、/etc/login.conf は変更せず、class フィールドも使用せず、各自 LANG 変数をセットするほうが楽と思われます。私の会社のように多国籍企業の場合、ブラジルのオフィスの人でも、ポルトガル語をしゃべるとは限りません。近隣の国のようにスペイン語をしゃべる人もいるでしょう。なので、基本ロケールは変更せず英語のままで各自必要に応じて変更しています。というか、基本みんな英語で大丈夫です 🙂

PAGER / EDITOR

PAGER 変数は何かのアプリケーションが長いテキストファイルを表示するときに PAGER 変数にセットした PAGER を使用して表示できるようになります。例えば、PAGER が less にセットされているとき、man ls とすると、

と、less を使用してページごとに見ることができます。他の例で、more にしてみると、

PAGER を more にしてみる。
PAGER が more コマンドになる。

指定通り、more が使用されます。ページャ以外のコマンドを指定しても構いません。例えば、wc にしてみると、

となり、man ls の行数が表示されました。EDITOR変数もPAGERとよく似ており、デフォルトで起動させるエディタを指定できます。LANG 変数のところで使用した vipw なども、EDITOR 変数に vi と指定しているので、vi エディタが起動します。これを例えば emacs などと指定すると、emacs エディタが起動します。

BLOCKSIZE

デフォルトでは BLOCKSIZE は ‘K’ にセットされています。これが効いてくるコマンドの例として df があります。超巨大ファイルシステムを持つサーバーでデフォルトの ‘K’ を使用していると数字の桁がが大きくなりすぎるので、適切なブロックサイズにしてみましょう。

COLUMNS / LINES

この値はフルスクリーンアプリケーションの動作に影響してきます。例えば、フルスクリーンエディタでファイルを開くと、画面は24行80カラムであるとして動作します。ですので、画面いっぱいをうまく使うことができます。24×80 は端末と呼ばれる装置の代表である vt100 がその仕様になっていたことから来ています、FreeBSD のデフォルトの端末タイプが vt100 となっているので、24×80 が標準となっています。Tera Term の中にも端末タイプを指定するところがあります。

これらの値を変えて vi エディタなどを起動すると違った動きをします。例えば、いずれも半分にしてみます。

縦横半分にしてみます。

縦も横も画面の半分だけを使用して vi コマンドを使用することができました。

これは余談ですが、このようにフルスクリーンを取り扱うアプリケーションを作成するのに必要なライブラリを curses ライブラリ ( man curses ) と呼び、このマニュアルに従って書いた C 言語のプログラムでフルスクリーンのアプリケーションを実現することができます。X11 があるじゃないか?といわれる方もいらっしゃると思いますが、私のようにシステム管理を 100% CLI で行う輩には重要でありますし、また懐かしいものなのです。昔に rogue と呼ばれるフルスクリーンのゲームで仕事の合間に遊んだことを覚えています。今のスマホのゲームのような派手さは全くありませんが、想像力を掻き立ててくれたゲームで未だに覚えています。現在の FreeBSD には見当たらないのですが、個人的には curses ライブラリを使用した傑作ゲームと思っています。お時間のある方はお試しあれ。

TERM

先の LINES や COLUMNS とも関係のある変数なのですが、テキストをフルスクリーンで編集するためにコントロールコードを出力してカーソルポジションを動かすのですが、その時に端末タイプとして何が接続されているかをこの変数で指定してやります。

Tera Term の設定の中に terminal id というオプションがあります。

この terminal id と TERM 変数が一致しているとフルスクリーンエディタとしてまともに機能するようになります。

もし互換性のない端末を指定するとどうなるかというと、

例えば IBM を指定してみる。

とてもフルスクリーンで動作しているようには見えません。

如何ともしがたい状態に….. vi コマンドの :q! を入力して終了する

ただし、Tera Term の terminal id に IBM があるとすると、それを選択することでフルスクリーンで動くようになります。つまり、OS 側から出されるコントロールコードを端末側が正しく認識できるということです。

DEC の VT シリーズは永遠の標準です。

世の中の代表的な端末タイプは /etc/termcap というファイルに定義されています。このファイルがないと、vi でファイルを編集して、最下行の次の行にカーソルを移動したときに何も起こりません。それ以前にカーソルを移動することもできないでしょう。この制御コードが定義されているおかげで、最下行にもう一行表示するために、それ以前の行を1つずつ上の行に移動して、1行目にあった行は消去する等々、非常に複雑なやり取りを端末との間で行っています。

vt100 の制御コードです。

PS1

PS1 はコマンドのプロンプトの設定です。デフォルトは “\u@\h:\w $” になっています。これは ksh のデフォルトということではなく、sh のデフォルトを ksh が引き継いでいるという状況にあります。ですので、この状態で /bin/sh を動かしてみると、この呪文のような文字列の意味するところが分かります。

ユーザ名@ホスト名:カレントディレクトリ

これと同じ情報を ksh で実現しようとすると少々困ります。pdksh のソースコードを見る限り、プロンプトでダイナミックに表示が変わるのは ! だけとなっています。

プロンプトの ! はコマンドの履歴の番号を表します。ですので、この例の2番目のコマンドを再度実行したい場合は、

履歴を使えます。

とキー入力を減らせます。

ENV

ENV 環境変数は ksh コマンド自身の動きをカスタマイズするためのファイルです。中身の説明は後程。

PATH

PATH 変数は入力したコマンドがどのディレクトリのコマンドを実行するかの順番を指定します。こちらが今私が使用している FreeBSD の デフォルトの PATH です。

どのような動きをするかというと、例えば、vim と入力したとしますと、vim コマンドを /sbin にあるかどうか探して、なければ /bin を探して、/usr/sbin .. /usr/bin .. /usr/local/sbin … /usr/local/bin … と探して行き最後に /home/pokemon/bin ディレクトリを探す。そして、どこにも見つからなければ not found とエラーを表示する。という動きになります。では、vi コマンドであればどうでしょう?

vim と同様に探して行き、/usr/bin に vi コマンドがあるので、その vi コマンドを実行します。では複数の vi コマンドがあった場合どのようになるでしょう?/home/pokemon/bin ディレクトリに vi という空ファイルを作成し、実行パーミッションを与えておきました。

もし、/usr/bin に vi コマンドがなければ、/home/pokemon/bin/vi が使われるはずです。でも、/usr/bin/vi があるので、/home/pokemon/bin/vi は使われません。このようにどのディレクトリにあるコマンドが優先されるのかを PATH で指定できるのです。では、デフォルトで提供されている順番でよいでしょうか?歴史的に /usr は別パーティションにマウントされることが多かったため、/bin や /sbin にはシングルユーザモードでのファイルシステム修復など、基本的なコマンドが収められており、それ以外は /usr/bin や /usr/sbin に収められることが多くなっています。/usr/local/bin や /usr/local/sbin には、/bin や /usr/bin などにあるコマンドの上位互換バージョンや基本 OS には含まれない独自のコマンドなどが収められます。pkg コマンドでインストールされたコマンドもこれに含まれます。さて、最後に /home/pokemon/bin ですが、一般的には /usr/local/bin に入れたいコマンドの開発中版のコマンドや、自分だけで使用するカスタムスクリプトなどが置かれます。ですので、本来的には /home/pokemon/bin が一番最初で、続いて /usr/local/bin、最後に /bin や /usr/bin の順番にするのが論理的な並びと考えます。え?何故 /usr が別パーティションに?別の記事でも書いた記憶があるのですが、当時のディスクはサイズが非常に小さく、複数のディスクドライブで1つの OS をインストールするようなことを日常的に行っていました。ですので、ルートファイルシステムに全部入れるようなことができなかったケースがほとんどでしたので、/bin と /usr/bin に分かれているということです。今は、何も考えず、ルートファイルシステムのみで、それ以外はスワップとブートだけというシステムがほとんどのようです。

最後にこれらのお好みの変更を $HOME/.profile ファイルに書き込んでおきます。そうすると、ログインの度に設定しなおす必要がなくなります。

私はこんな風にしてみました。

PATH はご説明した通りの順番に、TERM も明示的に vt100 にセットして、PS1 にシステム/ユーザ情報をコマンドから取得してセットするようにしました。別途の記事となりますが、M$ Active Directory でユーザ管理をしたりしたときにドメイン部を削除したり、ホスト名も FQDN のドメイン部を捨てるようにしています。会社では、私はこれをもう少し複雑にしたものを、NFS マウントした /home 配下の自分のホームディレクトリに置いています。仕事場の環境では同じような Tera Term の窓が沢山開いているので、どのサーバにどの権限でつながっているのかが一目でわかります。FreeBSD ではないのですが、一部の Linux は root での ssh 接続を受け付けたりするので、そのことを忘れて下手な文字列をコピーペーストしてしまうと、開いた口がふさがらなくなることがあるので、これは ( 私にとって ) 非常に重要です 🙂 環境変数自体は山ほど種類がありますので、必要に応じて適当にセットしましょう。

ALIASES

さて、2つ目のカスタマイズは ksh 自身のカスタマイズを行います。そのファイルが上のほうにも出てきた .shrc ファイルです。本来このファイルは /bin/sh 用のファイルで、/bin/ksh デフォルトのファイル名は $HOME/.kshrc になっていると思います。今回は ENV 変数がセットされているので /bin/sh の環境をそのまま使ってみたいと思います。まずはエディタで開いてみましょう。

このような感じになっています。このファイルの PS1 がコメントになっていますが、PS1 を $HOME/.profile で変更をかけたにもかかわらず、何も変化がなかったので調べてみると、$HOME/.shrc に PS1 をセットするところがありました。ということで、このファイルの PS1 は私の手でコメントアウトしました。その結果、上のようなプロンプトになります。

基本的なカスタマイズは alias コマンドで、自分の使いやすいようにコマンドを叩けばよいようにしていけばよいと思います。私の場合は、Linux などともホームディレクトリを共用していますので、OS により微妙にコマンドを変えています。

システム管理をされる方はお分かりと思いますが、いとも簡単にシステムを再起不能にもできてしまいます 🙂 ですので、この be paranoid の部分は生かしておいたほうがお勧めです。

アッ!と思ったときに消してもいいか?と聞いてきてくれるので 🙂

後は、man ksh と叩いてマニュアルを見て、ほしいなと思う機能を設定してください。私の会社の環境では、FreeBSD, Linux 入り乱れた環境ですので、この例のように単純ではありませんが、基本的な考えは、FreeBSD でも Linux でも Solaris でも、できる限り同じような使い勝手を確保できるようにする。。。というのが目的になると思います。

最後に、rogue をもう一度楽しんでみたいと思い、探してみました。FreeBSD のパッケージはありませんし、別途の記事でお話しする ports にもありませんでした。ネットの情報を頼りに探してみると、オリジナルの rogue のソースコードがこちらにあることがわかりました。早速ダウンロードしてコンパイルしてみました。まずは zip ファイルをダウンロードしてきます。そして、普通に configure を走らせます。念のために ncurses を使用するというオプションを付けます。

configure が完了したので、普通に make してみます。

構造体 TERMINAL に使用されている別の構造体 term の定義が足りないと宣われます 🙁

term.h を眺めてみます。と、構造体 term は NCURSES_INTERNALS が定義されていると実体が使えそうです。

configure でできた Makefile を編集して、

コンパイルオプションを付け加えます。

make で出来上がったオブジェクトをきれいに消してから再度 make をかけます。

きれいに通ったようです。出来上がったプログラムを実行してみます。

おぉ!懐かしの rogue です (T T) 。

使い方は make で作成された rogue.cat を見てください。

遊び方は、四角に囲まれた洞窟内部や洞窟間の通路を歩き回り、落ちているものを拾ったり、現れるモンスターを倒したりして、どんどん地下深くへ進んでゆくゲームです。今どきで言うと、ドラゴンクエストをイメージしてもらえればそう大きく外れていないと思います。ご興味があれば試し点てください。

以下広告


コメント