  Bash Prompt HOWTO
  Giles Orr, giles@interlog.com
  $Revision: 1.3 $, $Date: 2001/09/07 17:04:58 $
  遠藤 明 <akendo@t3.rim.or.jp>
  v0.60j, 19 January 1999

  端末と xterm でのプロンプトの作成と制御の解説で、ユーザー名、現在の
  ディレクトリ、時間などを表示する標準のエスケープ・シーケンスを含んでい
  ます。xterm のタイトルバーを変えたり、プロンプトに外部関数を使った情報
  をいれたり、ANSI カラーを使う方法も述べます。
  ______________________________________________________________________

  目次

  1. はじめに、
     1.1 前提
     1.2 このドキュメントの使い方
     1.3 翻訳
     1.4 問題
     1.5 コメントや提案を聞かせてください
     1.6 謝辞
     1.7 著作権と責任放棄

  2. BashとBashのプロンプト
     2.1 Bashとは
     2.2 Bash プロンプトをいじるとよいことがあるのですか?
     2.3 なぜ面倒なことをするの?
     2.4 第一段階
     2.5 Bashプロンプトのエスケープシーケンス
     2.6 PS?文字列の設定を永続させる

  3. 外部コマンド
     3.1 PROMPT_COMMAND
     3.2 プロンプトの中での外部コマンド
     3.3 プロンプトに何を置くか
     3.4 Bash の環境と関数

  4. Xtermのタイトルバーの操作
  5. ANSI エスケープシーケンス: 色とカーソル操作
     5.1 色
     5.2 カーソル操作
     5.3 tput でカーソルを動かす

  6. 特別な文字: 8進数エスケープシーケンス
  7. Bash Promptパッケージ
     7.1 入手方法
     7.2 Xterm のフォントを変える

  8. プロンプトを変える
     8.1 プロンプトを変える、後で
     8.2 プロンプトを変える、今すぐ

  9. 動的にプロンプトの色を変える
     9.1 どうすれば可能か

  10. プロンプトの例
     10.1 「軽量」プロンプト
     10.2 Bashpromptからelite
     10.3 「パワーユーザー」プロンプト
     10.4 端末幅のプロンプト
     10.5 役立たずのエレガントな時刻表示プロンプト

  ______________________________________________________________________

  1.  はじめに、

  1.1.  前提

  Bash が必要です。ほとんどの Linux についてくるバージョンは(これを書い
  ている 98年11月時点で)1.14.7で、有名で、信頼性の高いシェルです。 Bash
  のバージョンは、現在 2.0 以上になっており、私はここしばらく Bash 2.0
  を使っていますが、ここで示したほとんどのコードは1.14.7でも動きます。何
  か問題のあるところは、私が知っている限り、指摘しておきました。あなたの
  Bash のバージョンは、echo $BASH_VERSIONとプロンプトでタイプすると分か
  ります。私の機械では、2.02.1(1)-releaseとなります。

  シェル・プログラミングの経験は有用ですが、必須ではありません。知識が多
  ければ多いほど、より複雑なプロンプトをつくれることでしょう。このチュー
  トリアルを読むのに、シェル・プログラミングと Unix ツールの基本的な知識
  を仮定しましたが、そもそも私のシェル・プログラミングの知識は限定された
  ものですから、私は、沢山の例や説明を書きましたが、それらは経験を積んだ
  シェル・プログラマには不必要に思えるかもしれません。

  1.2.  このドキュメントの使い方

  例や説明を多くいれました。読む人が変われば、どの部分が役に立つと思うか
  も変わってくるでしょう。大きな文書になってきましたので、最初から通して
  読むことが難しくなってきています。読みたいところを拾い読みし、必要に応
  じて戻って下さい。

  1.3.  翻訳

  現在(1999年1月6日)、日本語(Akira Endo, akendo@t3.rim.or.jp)とドイツ
  語(Thomas Keil, thomas@h-preissler.de) への翻訳が進められています。お
  二人に感謝。URLが入手できたらつけ加えます。

  1.4.  問題

  これは、私がプロンプトをプログラムしていて気がついた問題点のリストで
  す。ここから読み始めてがっかりしないで下さい。これは細かな小さな問題で
  す。何か変なことが起こった時にここに戻って下さい。

  o  多くの Bash の機能(たとえば$(())の中での計算)は、コンパイル時のオプ
     ションです。標準の Linux ディストリビューションにはいってくるものの
     ように、バイナリーの Bash を使っているなら、このような機能はすべて
     コンパイルされているものと思います。しかし、もし他人のシステムで仕
     事をしているなら、期待していることがうまくいかなかった場合にこのこ
     とを思い出して下さい。これについては、 Learning the Bash Shell,
     p.260-262に記載があります。

  o  端末のスクリーンマネージャー"screen"は、必ずしもANSIカラーをサポー
     トしているとは限りません。残念ながら私は screen についてそれほど詳
     しくありません。私の screen のバージョンは非常に新しいもので、すべ
     ての場合にうまくいっていますが、X 端末上で、プロンプトの色が標準の
     フォアグラウンドカラー一色になってしまうことがありました。このよう
     なことはコンソールでは生じないようです。

  o  Xdefaults ファイルで色を変えていることがあります。 /.Xdefaults の中
     で、 XTerm*background や XTerm*foreground (あるいは
     XTerm*Background や XTerm*Foreground) の記述がないか調べて下さい。

  o  この文書の中で"jobs"の出力を使っているプロンプトがあり、そこで述べ
     ますが、 Bash 2.02 では、"jobs"の出力をパイプに渡すところがうまくい
     きません。

  o  ANSI カーソル操作シーケンスは、すべてのX端末で実現されているわけで
     はありません。その章で述べます。

  o  見栄えのする疑似グラフィックは、Linux 標準のフォントではなく、VGA
     フォントによって表示されます。残念ながらこれは VGA フォントを使わな
     いとひどい姿になります。またどんなフォントを使っているかを端末の中
     で調べる方法がありません。

  o  Bash 2.0+ が出されており、新しい機能が付加され、ある機能のふるまい
     が異なっています。1.14.7で動いていたものが2.0+で動かなかったり、ま
     た逆の場合があり得ます。

  1.5.  コメントや提案を聞かせてください

  これを書くことが私にとっての勉強にもなりました。興味深い役に立つ Bash
  プロンプトを書くことができるようになりました。でも、この文書の誤りを直
  し、改善していくには、あなたからの感想が必要です。私の示したものをバー
  ジョンの異なる Bash (多くは私が使っている2.02で、また広く使われてい
  る1.14.7でも)でチェックしてみましたが、何か不都合な点があれば知らせて
  下さい。

  この文書の最新版は http://www.interlog.com/~giles/bashprompt.html から
  入手可能ですので、ここをチェックして下さい。そして、私
  giles@interlog.comに気軽に e-mail を送り、ご意見をお聞かせ下さい。

  私は LDP の HOWTO をほとんど HTML フォーマットで使っています。したがっ
  て、この文書を SGML から変換してよくチェックしたのは、HTML だけです。
  他のフォーマットで問題があっても分かりませんので、知らせていただければ
  幸いです。

  1.6.  謝辞

  この文書を書くために http://bash.current.nu/ の Bashprompt プロジェク
  トから非常に多くのものを借りました。その他、
  http://sunsite.unc.edu/LDP/HOWTO/mini/Xterm-Title.htmlで入手可能な Ric
  Lister によるxterm Title mini-HOWTO、
  http://www.ncal.verio.com/~keebler/ansi.htmlで入手可能な Keebler によ
  るAnsi Prompts、 http://bash.current.nu/bash/HOWTO.htmlで入手可能な
  Stephen Webb によるHow to make a Bash Prompt Theme、
  http://home.earthlink.net/~us5zahns/enl/ansifont.htmlで入手可能な
  StumpyによるX ANSI Fontsもためになりました。

  私よりずっと深い Unix の知識を持つ Georgia College & State University
  の同僚 Dan からの e-mail も助けになりました。多くの素晴らしい提案をし
  てくれ、また彼の考えによっておもしろいプロンプトができました。

  プロンプトをプログラムするために、3冊の本がとても役に立ちました。
  Linux in a Nutshell Jessica Heckman Perry (O'Reilly, 1997)、 Learning
  the Bash Shell Cameron Newham and Bill Rosenblatt (O'Reilly, 2nd. ed.,
  1998)、 Unix Shell Programming Lowell Jay Arthur (Wiley, 1986、これは
  第1版で第4版が1997年にでました)です。

  1.7.  著作権と責任放棄

  This document is copyright 1998-1999 by Giles Orr.  You are encouraged
  to redistribute it.  You may not modify this document (see the section
  on contacting me: I have so far been incorporating all changes
  recommended by readers).  Please contact me if you're interested in
  doing a translation: that's one modification I can live with.

  この文書の著作権は、Giles Orr、1998-1999 が有しています。どうぞ再配布
  をお願いします。この文書を改変してはなりません(私へのコンタクトの章を
  読んで下さい。これまで読者から受けた提案はこの中に含めてあります)。翻
  訳したい方は私にコンタクトして下さい。これが私の許可する唯一の改変で
  す。

  This document is available for free, and, while I have done the best I
  can to make it accurate and up to date, I take no responsibility for
  any problems you may encounter resulting from the use of this
  document.

  この文書は無料で入手できます。できるだけ正確で最新のものにしたつもりで
  すが、この文書を使用してあなたが遭遇するどんな問題にも責任はとりませ
  ん。

  2.  BashとBashのプロンプト

  2.1.  Bashとは

  Bourne Shell の流れをくむ Bash は、GNU で開発されており、 Bourne Again
  SHell から名付けられています。多くの Linux では標準のコマンドライン・
  インターフェースになっています。対話性や、コマンドラインの編集、補完、
  履歴といった機能に卓越しています。プロンプトを設定変更できることは多く
  の人が知っていますが、どこまでのことができるかはあまり知られていませ
  ん。

  2.2.  Bash プロンプトをいじるとよいことがあるのですか?

  多くの Linux のデフォルトのプロンプトは、1色(通常グレイ)で、ユーザー
  名、マシン名、現在のディレクトリを示すものになっています。これは役に立
  つ情報です。でもプロンプトはもっと多くのことを示せます。どんな情報でも
  示すことができます。tty 番号、時間、日付、負荷状態、ユーザー数、接続時
  間等々。プロンプトには ANSI の色が使え、見た目を面白くしたり、ある情報
  を際立たせたりできます。このような情報を示すために、Xterm のタイトルバ
  ーを操作することもできます。

  2.3.  なぜ面倒なことをするの?

  かっこよく見せるというだけでなく、システム情報が示されるのは役に立つこ
  とが多いでしょう。異なった機械では異なった色でプロンプトを出すというよ
  うなことに使う人もいます。いくつもの Xterm をいくつもの機械で動かして
  いたり、どの機械を動かしているのかを勘違いして、間違ったファイルを削除
  したりするような人は、このような工夫をすることによって、どの機械を動か
  しているかを忘れることがなくなるでしょう。

  2.4.  第一段階

  プロンプトの形状はシェル変数 PS1 によって決まります。コマンドが2行以上
  になる時の2行目以降のプロンプトは、PS2 の文字列で決まります。これは
  PS1 と全く同じ書き方ですので、この文書ではほとんど PS1 についてだけ述
  べます。(PS3 と PS4 という変数もあります。これらは通常のユーザーが見る
  ことはありません。もし興味があれば、Bash の man ページを見てくださ
  い。)プロンプトを変えるには、PS1 を変えます。実験してみるには、PS1 の
  文字列を直接プロンプトのところで変えてみて下さい。結果がすぐに表れるで
  しょう。 (この変化は現在の環境を変えるだけで、ログアウトすればなくなっ
  てしまいます。) もしプロンプトを永久に変えたければ、 /.bashrc に PS1
  の新しい定義を置いて下さい。もし、ルート権限を持っているな
  ら、/etc/profile ファイルの中の"PS1="の行を変えます。Linux のディスト
  リビューションの種類によっては(RedHat 5.1ではそうですが)/etc/bashrc が
  PS1 と PS2 の設定を変えますので、注意してください。

  はじめに注意しておきますが、PS1 の設定は他の環境変数と同様、環境に保存
  されています。PS1 の設定をコマンドラインで変化させれば、プロンプトが変
  わります。変更する前に現在のプロンプトを保存したければ、別の環境変数に
  保存しておいてください。

  [giles@nikola giles]$ SAVE=$PS1
  [giles@nikola giles]$

  もっとも簡単なプロンプトは1文字からなるものです。たとえば

  [giles@nikola giles]$ PS1=$
  $ls
  bin   mail
  $

  簡単なプロンプトを実験するには、このようにコマンドラインで入れます。ユ
  ーザーが入力する文字がプロンプトの直後に表れることに注意して下さい。私
  は次のようにプロンプトを設定する方が好きです。

  $PS1="$ "
  $ ls
  bin   mail
  $

  こうすることによって、プロンプトの次にスペースが置かれ、読みやすくなり
  ます。もとのプロンプトに戻すには、保存しておいた変数を呼び出します。

  $ PS1=$SAVE
  [giles@nikola giles]$

  2.5.  Bashプロンプトのエスケープシーケンス

  Bash には、プロンプトで使えるエスケープシーケンスが沢山あります。 Bash
  2.02 の man ページをみると、

  対話型で実行される時には、bash はコマンド待ちの状態で、一次
  プロンプトの PS1 を表示し、コマンドを完成するのにさらに入力が
  必要な時には二次プロンプトの PS2 を表示します。bash ではバック
  スラッシュでエスケープした文字を挿入することにより、プロン
  プトを修飾することができます。その意味は次のとおりです。
         \a     ASCII のベル文字 (07)
         \d     "曜日 月 日"のフォーマットによる日付け
                (例 "Tue May 26")
         \e     ASCII のエスケープ文字 (033)
         \h     最初の"."のところまでのホスト名
         \H     ホスト名
         \n     改行
         \r     復帰
         \s     シェル名、$0 のベース名
                (最後のスラッシュの後ろの部分)
         \t     24時間制の HH:MM:SS のフォーマットによる時間
         \T     12時間制の HH:MM:SS のフォーマットによる時間
         \@     am/pm をつけた12時間制のフォーマットによる時間
         \u     現ユーザーのユーザー名
         \v     bash のバージョン(例 2.00)
         \V     bash のリリース番号、バージョンとパッチレベル
                (例 2.00.0)
         \w     現在のディレクトリ
         \W     現在のディレクトリのベース名
         \!     現在のコマンドのヒストリー番号
         \#     現在のコマンドのコマンド番号
         \$     UIDが0なら#、そうでなければ$
         \nnn   8進数nnnに対応する文字
         \\     バックスラッシュ
         \[     表示されない文字列の開始。端末制御シーケンスを
                プロンプトに埋め込む。
         \]     表示されない文字列の終り。

  それでは続きです。

  [giles@nikola giles]$ PS1="\u@\h \W> "
  giles@nikola giles> ls
  bin   mail
  giles@nikola giles>

  これはデフォルトのプロンプトとほとんど変わりありません。そこで少しスタ
  イルを変えてみましょう。

  giles@nikola giles> PS1="[\t][\u@\h:\w]\$ "
  [21:52:01][giles@nikola:~]$ ls
  bin   mail
  [21:52:15][giles@nikola:~]$

  2.6.  PS?文字列の設定を永続させる

  多くの人、多くのディストリビューションが PS? 文字列を異なったところで
  設定しています。一番多いの
  は、/etc/profile、/etc/bashrc、 /.bash_profile 及び /.bashrcで
  す。Johan Kullstam (johan19@idt.net)は書いています。

  PS1 文字列は .bashrc で設定すべきです。非対話型 bash は PS1 の設定をクリアして
  しまうからです。bash manページには、bashが対話型セッションにあるか、非
  対話型(つまりスクリプト)セッションにあるかを知るよい方法がPS1が定義され
  ているかどうかだと書いてあります。

  これを私が理解したのはstartxがbashスクリプトで、startxはあなたのプロン
  プトを消してしまいます。.profile(もしくは.bash_profile)でPS1を設定し、
  コンソールでログインして、startxでXを起動すると、あなたのPS1は破壊され
  てしまい、デフォルトのプロンプトに戻ります。

  解決法の一つは、xtermやrxvtを-lsオプション付きで起動し、.profileファイ
  ルを読み込むようにすることです。しかし、非対話型のシェルスクリプトによ
  ってシェルが呼ばれる度にPS1が失われます。system(3)は sh -c を使いますが、
  sh が bash なら PS1 が失われます。よりよい解決法は、PS1 の定義を .bashrc に
  置くことです。これは bash が起動される度に読み込まれますので、PS1 のような
  対話に必要なものを置くべき場所です。

  したがって、「PS1=何たらかんたら」は、.profile ではなく、.bashrc に置か
  れるべきです。

  私は彼の説明を再現しようとして別の問題にぶちあたりました。私の
  PROMPT_COMMAND 変数(次に説明します)がなくなってしまうのです。この分野
  での私の知識は十分でないので、Johan が言うようにしましょう。

  3.  外部コマンド

  3.1.  PROMPT_COMMAND

  Bash には、PROMPT_COMMAND という環境変数があります。この内容は Bash が
  プロンプトを出す前に普通の Bash のコマンドとして実行されます。

  [21:55:01][giles@nikola:~] PS1="[\u@\h:\w]\$ "
  [giles@nikola:~] PROMPT_COMMAND="date +%H%M"
  2155
  [giles@nikola:~] d
  bin   mail
  2156
  [giles@nikola:~]

  ここでは、\tエスケープシーケンスは PS1 の中にはありませんので、プロン
  プトには時間情報が含まれません。date +%H%Mによって私の好みのフォーマッ
  トで時間が表示されます。しかし、時間がプロンプトと別の行に表れま
  す。Bash 2.0+ では、echo -n ...を使ってこれを直すことができます
  が、Bash 1.14.7 ではできないようです。プロンプトの表示方法が異なってお
  り、テキストが2回表示されるようになってしまいます。

  2156
  [giles@nikola:~] PROMPT_COMMAND="echo -n [$(date +%H%M)]"
  [2156][giles@nikola:~]$
  [2156][giles@nikola:~]$ d
  bin   mail
  [2157][giles@nikola:~]$ unset PROMPT_COMMAND
  [giles@nikola:~]

  echo -n ...は date コマンドの出力を制御し、最後の改行を抑制することに
  よって、プロンプトが1行で表示されるようになります。最後に unsetコマン
  ドを使って、環境変数 PROMPT_COMMAND を除きます。

  コマンド展開を行なうのに、$(<command>)という書き方を使っていることに注
  意してください。つまり、

  $(date +%H%M)

  は、「date +%H%Mのコマンドの出力で置換する」という意味です。これ
  は、Bash 2.0+ では動きますが、1.14.7 以前の Bash では、バッククォート
  を使って、`date +%H%M`とします。Bash 2.0+ でもバッククォートは使えます
  が、$()の方がネストしやすいので使われなくなっています。この文書ではこ
  の書き方を使っていきます。もしあなたの使っている Bash が古いバージョン
  なら、$()の代わりにバッククォートを使ってください。コマンド展開がエス
  ケープされている時(つまり \$(command) )は、バッククォートを両方エスケ
  ープ(つまり \`command\` )してください

  3.2.  プロンプトの中での外部コマンド

  普通の Linux のコマンドの出力を直接プロンプトに埋め込むこともできま
  す。たくさんのものを埋め込もうとはしないでください。プロンプトが長くな
  りすぎます。あなたは速いコマンドを使いたいとも思っているでしょう。プロ
  ンプトが画面に表示されるたびに実行されて、作業中にプロンプトの表示に時
  間がかかるとイライラしますから。(前の例に似ていますが、これは Bash
  1.14.7 でも動作します。)

       [21:58:33][giles@nikola:~]$ PS1="[\$(date +%H%M)][\u@\h:\w]\$ "
       [2159][giles@nikola:~]$ ls
       bin   mail
       [2200][giles@nikola:~]$

  コマンド展開のドル印の前にあるバックスラッシュに注意して下さい。これが
  ないと外部コマンドは、PS1 文字列が環境に読み込まれる時にたった一度だけ
  しか実行されません。このプロンプトの場合には、どんなに長くプロンプトが
  使われても、いつも同じ時間を表示することになります。バックスラッシュを
  置くことによって、$()の内容がすぐには実行されなくなり、"date" はプロン
  プトが生成される度に実行されることになります。

  Linux には多くの小さなユーティリティがついてきます。date、 grep、 wcな
  どでデータを操作できます。このようなプログラムを使って複雑なプロンプト
  を作るには、シェルスクリプトを作って、それをプロンプトから実行させた方
  がいいでしょう。スクリプトの中でもコマンドが正しい時に実行されるよう、
  エスケープシーケンスが必要になることがあります(上のdateコマンドの例の
  ように)。PS1の行の中ではレベルが一段上がることになりますので、シェルス
  クリプトを作ることによりこれを避けるのはよい考えです。

  小さなシェルスクリプトをプロンプトの中で使う例を示しましょう。

  ______________________________________________________________________
  #!/bin/bash
  #     lsbytesum - sum the number of bytes in a directory listing
  TotalBytes=0
  for Bytes in $(ls -l | grep "^-" | cut -c30-41)
  do
      let TotalBytes=$TotalBytes+$Bytes
  done
  TotalMeg=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc)
  echo -n "$TotalMeg"
  ______________________________________________________________________

  このようなものを関数(の方が効率的ですが、この文書では関数の書き方は残
  念ながら扱いません)にしたり、パスの通っている  /bin ディレクトリの中に
  シェルスクリプトとして保存しておきます。プロンプトの中での使い方は、

       [2158][giles@nikola:~]$ PS1="[\u@\h:\w (\$(lsbytesum) Mb)]\$ "
       [giles@nikola:~ (0 Mb)]$ cd /bin
       [giles@nikola:/bin (4.498 Mb)]$

  3.3.  プロンプトに何を置くか

  私が示すプロンプトの例では、ほとんどいつもユーザー名、機械名、時間、現
  在のディレクトリ名が表示されることにお気づきでしょう。時間を除けば、こ
  れらはプロンプトに表示される標準のもので、時間はおそらくその次に追加さ
  れることの多いものでしょう。でも何をいれるかは、全く個人の趣味にかかる
  ものです。ここでは、私の知っている人たちの例を示してあなたに参考にして
  もらいましょう。

  Danのプロンプトは短いけれども効果的です。特に彼の仕事のやり方にとっ
  て。

  [giles@nikola:~]$ cur_tty=$(tty | sed -e "s/.*tty\(.*\)/\1/")
  [giles@nikola:~]$ echo $cur_tty
  p4
  [giles@nikola:~]$ PS1="\!,$cur_tty,\$?\$ "
  1095,p4,0$

  Danは、ディレクトリツリーを動き回っている間、プロンプトの長さが急に大
  幅に変わるので、現在のディレクトリを表示するのは好きではありません。だ
  からそれは頭にたたき込んでおきます(またはpwdコマンドを使います)。彼は
  Unix を csh や tcsh で学んだので、コマンドヒストリーをよく使いま
  す(Bash 使いはあまりそうはしないようです)ので、プロンプトの最初にヒス
  トリ番号を表示します。次に(tty コマンドの出力を sed で加工して)tty の
  文字列の中の特徴的な部分を表示します。これは "screen" を使っている人の
  役に立ちます。三番目に、最後に使ったコマンドやパイプラインの exit 値を
  表示します(これはプロンプトから実行されるコマンドでは意味がありません
  ので、exit値を別の変数に捕えて表示するようなことを考える必要がありま
  す)。最後に \$ で通常のユーザーでは $ を、root に対しては # を表示する
  ようにします。

  Torben Fjerdingstad は、時々ジョブをサスペンドし、そのことについて忘れ
  てしまうので、サスペンド中のジョブを思い出させてくれるプロンプトを使っ
  ているとメールしてくれました。

       [giles@nikola:~]$ function jobcount {
       > jobs|wc -l| awk '{print $1}'
       > }
       [giles@nikola:~]$ export PS1='\W[`jobcount`]# '
       giles[0]# man ls &
       [1] 4150

       [1]+  Stopped (tty output)    man ls
       giles[1]#

  Torben は、awkで wc の出力の中のスペースを削っています。私なら sed か
  tr を使うことでしょう。その方がいいからではなく、その方が慣れているか
  らです。他の方法もあることでしょう。Torben は PS1 文字列をシングルクォ
  ートで囲んでいますが、これは Bash がバッククォートを直ちに解釈するのを
  防ぎます。私が述べたエスケープの方法は使っていません。

  注意: Bash 2.02 にはシェルの組み込みコマンドである jobs がパイプに何も
  渡さないというバグが知られています。上のコードを Bash 2.02 で試すと、
  サスペンドしたジョブがいくつあっても0が帰ってきます。Bash の保守をして
  いる一人である Chet Ramey は、v2.03 ではこれを直すと言っています。

  3.4.  Bash の環境と関数

  すでに述べたように、PS1、PS2、PS3、PS4、PROMPT_COMMAND はすべて Bash
  の環境に保存されます。私たちのように DOS からきたものにとって、 DOS の
  環境領域は狭く、うまく拡張できなかったので、環境に多くの文字をいれるの
  は恐怖です。おそらく環境の大きさには実際上の上限があるのでしょうが、私
  は知りませんし、DOS ユーザーが慣れていた大きさの何倍ものオーダーの話な
  のでしょう。Dan は次のように言っています。

  「私の使っている対話型のシェルには、エイリアスが62と関数が25ある。対話
  型だけで使うもので、簡単に bash で書ける場合は、関数にしている (エイリ
  アスで書くには難しい場合)。もしメモリが気になるなら、bash を使わない方
  がいいだろう。bash は私の linux box で動いているプログラムの中で
  Oracle の次に大きい。top コマンドを時々動かして、M を押してメモリの大
  きさでソートしてごらん。bash がほとんど一番上に近いところにあるのがわ
  かるだろう。sendmail より大きいんだよ! メモリが気になるなら ash のよう
  なものを使えばいい。」

  こう書いた時彼はコンソールだけを使っていたのでしょう。X や X アプリケ
  ーションを動かせば、Bash より大きいのがいっぱいあります。でも考え方は
  同じです。環境は使うべきもので、使い過ぎを心配する必要はないのですか
  ら。

  こう書くと、Unix の導師たちには単純化しすぎていると検閲を受けるかもし
  れません。しかし関数は基本的に小さなシェルスクリプトで、効率のために環
  境に読み込まれています。Dan の言葉を借りれば「シェル関数は、限界に近い
  ところまで効率的だ。シェルスクリプトを source するのとほぼ同様のことを
  ファイル入出力なしに実行できる。すでにメモリに読み込まれているからだ。
  シェル関数は通常ログインシェルかサブシェルかによって、.bashrc か
  .bash_profile ファイルから読み込まれる。シェルスクリプトを動かす場合に
  は、現在のシェルは fork し、子プロセスが exec を行ない、おそらくパスが
  探され、カーネルはファイルを開き、実行するのに十分なメモリがあるか確か
  め、シェルスクリプトであった場合には新しいシェルをスクリプト名を引数と
  して与えて起動し、そのシェルがファイルを開いて、各行を実行する。シェル
  関数の場合と比べると、各行を実行する以外の部分は不必要なオーバーヘッド
  にすぎない。」

  4.  Xtermのタイトルバーの操作

  表示されないエスケープシーケンスはプロンプトに興味深い効果をもたらすた
  めに用いられます。このようなエスケープシーケンスを用いるには、\[ と \]
  で囲んでやり、Bashがプロンプトの大きさを計算する時に無視させます。この
  区切りを入れてやらないと、行編集の際のカーソルの位置の計算が違ってきま
  す。エスケープシーケンスは、バージョン2より以前の Bash では \033[ から
  はじめ、それ以降のバージョンでは、\033[ でも \e[ でもはじめることがで
  きます。

  コンソールを使っている時に Xterm のタイトルバーを変えようとすると、プ
  ロンプトにごみが入ります。これを避けるには環境変数 TERM を調べて、
  Xterm の時だけそのプロンプトを使うようにします。

  ______________________________________________________________________
  function proml
  {
  case $TERM in
      xterm*)
          local TITLEBAR='\[\033]0;\u@\h:\w\007\]'
          ;;
      *)
          local TITLEBAR=''
          ;;
  esac

  PS1="${TITLEBAR}\
  [\$(date +%H%M)]\
  [\u@\h:\w]\
  \$ "
  PS2='> '
  PS4='+ '
  }
  ______________________________________________________________________

  これは、 /.bashrc に書いておく関数です。この関数名を呼ぶと実行されま
  す。関数は、PS1 文字列と同様環境に置かれます。PS1 変数がこの関数で定義
  されたら、この関数をunset promlで環境から取り除くことができます。
  Xterm にいる間はコンソールに変わることがありませんから、変数TERMをプロ
  ンプトを出す度にチェックする必要はありません。継続行のしるし (バックス
  ラッシュ)をプロンプトの定義の中で使っているのは、複数行にまたがるよう
  にして、読み易さを増し、修正したり、デバッグするのを容易にしています。

  これを関数にしてあるのは、後で説明する Bashprompt パッケージのやり方で
  す。こうしなければならないということではありませんが、このやり方はうま
  くいきます。あなたの使うプロンプトが複雑になってくればくるほど、それを
  プロンプトのところでタイプするのは面倒になり、テキストファイルで保存す
  る必要が生じてきます。今回は上の関数を proml というテキストファイルに
  保存しましょう。次のようにします。

       [giles@nikola:/bin (4.498 Mb)]$ cd          -> プロンプトを保存したいディレクトリに移動
       [giles@nikola:~ (0 Mb)]$ vi proml           -> プロンプトファイルを編集
       ...                                         -> 上のテキストを入力
       [giles@nikola:~ (0 Mb)]$ source proml       -> プロンプト関数の読み込み
       [giles@nikola:~ (0 Mb)]$ proml              -> プロンプト関数の実行

  このプロンプトを作成する第一段階は、シェルが xterm かどうかをチェック
  することです。もしxtermなら、シェル変数(${TITLEBAR})が定義されます。そ
  の内容は適切なエスケープシーケンスと\u@\h:\wで、その結果、 <ユーザー
  名>@<マシン名>:<ディレクトリ>が Xterm のタイトルバーに表示されます。こ
  れは特に Xterm を最小化した時に同定しやすくしてくれます。このプロンプ
  トのそれ以外の部分はすでに今まで作ったプロンプトでおなじみのものです。

  このように Xterm のタイトルバーを操作する唯一のデメリットは、このよう
  なタイトルバーになるようにセットしていない機械を使ったとき、タイトルバ
  ーが元のままになってしまうことです。

  5.  ANSI エスケープシーケンス: 色とカーソル操作

  5.1.  色

  すでに述べたように表示されないエスケープシーケンスは、\[\033[ と \] で
  囲んでやる必要があります。色のエスケープシーケンスの場合は後ろに m\]
  をつけてやる必要があります。

  もしこれから説明するプロンプトを試してみて、指定した色がうまく表示され
  ないなら、 /.Xdefaults ファイル(あるいはそれと同等のファイル)に
  "XTerm*Foreground: BlanchedAlmond" のような行がないか調べてください。
  この前に!マークをつけることによって、コメントアウトすることができま
  す。これは、あなたがどのような端末エミュレータを使っているかにも依存し
  ます。あなたの端末の色が上書きされる可能性のもっとも高いのがこのファイ
  ルです。

  プロンプトにブルーのテキストを入れるには、

       PS1="\[\033[34m\][\$(date +%H%M)][\u@\h:\w]$ "

  このプロンプトの問題は、34のカラーコードで変えたブルーの色がもとの色に
  戻らないので、プロンプトの後にタイプした文字もプロンプトと同じ色になっ
  てしまうことです。また、このブルーは暗いので、bold コードも組み合わせ
  ます。

       PS1="\[\033[1;34m\][\$(date +%H%M)][\u@\h:\w]$\[\033[0m\] "

  プロンプトは明るいブルーに変わり、最後に色をなしにしています。(色なし
  は、元のフォアグラウンドカラーです。)

  色は次のように定義されています。

       Black       0;30     Dark Gray     1;30
       Blue        0;34     Light Blue    1;34
       Green       0;32     Light Green   1;32
       Cyan        0;36     Light Cyan    1;36
       Red         0;31     Light Red     1;31
       Purple      0;35     Light Purple  1;35
       Brown       0;33     Yellow        1;33
       Light Gray  0;37     White         1;37

  バックグラウンドカラーもこの方法で指定することができます。たとえば44な
  らブルー、41なら赤というふうになっています。バックグラウンドカラーには
  ボールドのものがありません。ブルーの背景にライトレッドのテキストを表示
  するなら、 \[\033[44;1;31m\] のように組み合わせて使うこともできまが、
  \[\033[44m\]\[\033[1;31m\] のように分けて設定した方がいいようです。他
  のコードとしては、4:下線、5:点滅、7:逆転、8:非表示などがあります。

  注:多くの人(私を含め)は、点滅属性に強く反対します。幸いこれは端末エ
  ミュレータでは作動しませんが、コンソールでは機能します。また、 (私がそ
  うであるように)非表示属性は何のためにあるのだろうと思うでしょう。 (プ
  ロンプトではなく)シェルスクリプトの例で、パスワードを入力してもスクリ
  ーンに表示されないように使われているのを見たことがあります。

  Bashprompt パッケージの中の elite2 というプロンプトを(元のが xterm の
  フォントで用いるようになっていたので、コンソールで使えるように)修正し
  たものは、私のよく使っていたものです。

  ______________________________________________________________________

  function elite
  {

  local GRAY="\[\033[1;30m\]"
  local LIGHT_GRAY="\[\033[0;37m\]"
  local CYAN="\[\033[0;36m\]"
  local LIGHT_CYAN="\[\033[1;36m\]"

  case $TERM in
      xterm*)
          local TITLEBAR='\[\033]0;\u@\h:\w\007\]'
          ;;
      *)
          local TITLEBAR=""
          ;;
  esac

  local GRAD1=$(tty|cut -d/ -f3)
  PS1="$TITLEBAR\
  $GRAY-$CYAN-$LIGHT_CYAN(\
  $CYAN\u$GRAY@$CYAN\h\
  $LIGHT_CYAN)$CYAN-$LIGHT_CYAN(\
  $CYAN\#$GRAY/$CYAN$GRAD1\
  $LIGHT_CYAN)$CYAN-$LIGHT_CYAN(\
  $CYAN\$(date +%H%M)$GRAY/$CYAN\$(date +%d-%b-%y)\
  $LIGHT_CYAN)$CYAN-$GRAY-\
  $LIGHT_GRAY\n\
  $GRAY-$CYAN-$LIGHT_CYAN(\
  $CYAN\$$GRAY:$CYAN\w\
  $LIGHT_CYAN)$CYAN-$GRAY-$LIGHT_GRAY "
  PS2="$LIGHT_CYAN-$CYAN-$GRAY-$LIGHT_GRAY "
  }
  ______________________________________________________________________

  色を一時的シェル変数として読み易いものに定義します。GRAD1 変数は使って
  いる端末を決めるのに用いています。Xterm 上かどうかのチェックと同様、こ
  れも一度行なえば十分です。結果は色を除けばこのように見えます。

       --(giles@nikola)-(75/ttyp7)-(1908/12-Oct-98)--
       --($:~/tmp)--

  どんな色が使えるのかを思い出すために、次のスクリプトはすべての色をスク
  リーンにエコーします。

  ______________________________________________________________________
  #!/bin/bash
  #
  #   このファイルは、様々なカラーコードを端末にエコーし、どんな色が
  #   使用可能かを示します。
  #   それぞれの行では、黒とグレイの背景の上に一つの色を示し、コードを中央に
  #   表示しています。白、黒、グリーンの背景色で確認してあります。(2 Dec 98)
  #
  echo "  On Light Gray:        On Black:"
  echo -e "\033[47m\033[1;37m  White        \033[0m\
   1;37m \
  \033[40m\033[1;37m  White        \033[0m"
  echo -e "\033[47m\033[37m  Light Gray   \033[0m\
     37m \
  \033[40m\033[37m  Light Gray   \033[0m"
  echo -e "\033[47m\033[1;30m  Gray         \033[0m\
   1;30m \
  \033[40m\033[1;30m  Gray         \033[0m"
  echo -e "\033[47m\033[30m  Black        \033[0m\
     30m \
  \033[40m\033[30m  Black        \033[0m"
  echo -e "\033[47m\033[31m  Red          \033[0m\
     31m \
  \033[40m\033[31m  Red          \033[0m"
  echo -e "\033[47m\033[1;31m  Light Red    \033[0m\
   1;31m \
  \033[40m\033[1;31m  Light Red    \033[0m"
  echo -e "\033[47m\033[32m  Green        \033[0m\
     32m \
  \033[40m\033[32m  Green        \033[0m"
  echo -e "\033[47m\033[1;32m  Light Green  \033[0m\
   1;32m \
  \033[40m\033[1;32m  Light Green  \033[0m"
  echo -e "\033[47m\033[33m  Brown        \033[0m\
     33m \
  \033[40m\033[33m  Brown        \033[0m"
  echo -e "\033[47m\033[1;33m  Yellow       \033[0m\
   1;33m \
  \033[40m\033[1;33m  Yellow       \033[0m"
  echo -e "\033[47m\033[34m  Blue         \033[0m\
     34m \
  \033[40m\033[34m  Blue         \033[0m"
  echo -e "\033[47m\033[1;34m  Light Blue   \033[0m\
   1;34m \
  \033[40m\033[1;34m  Light Blue   \033[0m"
  echo -e "\033[47m\033[35m  Purple       \033[0m\
     35m \
  \033[40m\033[35m  Purple       \033[0m"
  echo -e "\033[47m\033[1;35m  Pink         \033[0m\
   1;35m \
  \033[40m\033[1;35m  Pink         \033[0m"
  echo -e "\033[47m\033[36m  Cyan         \033[0m\
     36m \
  \033[40m\033[36m  Cyan         \033[0m"
  echo -e "\033[47m\033[1;36m  Light Cyan   \033[0m\
   1;36m \
  \033[40m\033[1;36m  Light Cyan   \033[0m"
  ______________________________________________________________________

  5.2.  カーソル操作

  ANSIエスケープシーケンスでカーソルをスクリーン上で自由に動かせます。こ
  れはシェルスクリプトでフルスクリーンのユーザーインターフェースを作る時
  に役に立ちますが、プロンプトでも使えます。カーソル操作エスケープシーケ
  ンスは次のとおりです。

       - カーソルの位置を決める。
         \033[<L>;<C>H
         カーソルを L 行 C 列に置きます。
       - カーソルを N 行上に動かす。
         \033[<N>A
       - カーソルを N 行下に動かす。
         \033[<N>B
       - カーソルを C 列右に動かす。
         \033[<>C
       - カーソルを C 列左に動かす。
         \033[<C>D

       - カーソルの位置を記憶する。
         \033[s
       - 記憶していたカーソルの位置に戻す。
         \033[u

  最後の二つのコードは多くの端末エミュレータで実現されていません。私の
  知っている限りでは、xterm と nxterm では実現されています。多くの端末エ
  ミュレータが xterm のコードに基づいているにもかかわらず。私が確認した
  限り、rxvt、kvt、 xiterm、Eterm はサポートしていません。コンソールでは
  サポートされています。

  次のコードをプロンプトにいれてみて下さい。(これが何をしているのかを
  はっきりさせるには、端末の上から何行か下でこれを実行して下さい。) echo
  -en "\033[7A\033[1;35m BASH \033[7B\033[6D" これは、カーソルを7行上に
  上げて" BASH "と表示し、元のプロンプトのところにカーソルを戻します。こ
  れはプロンプトではありません。何が起こっているかをはっきりさせるために
  色を変えて、カーソルをスクリーン上で動かしてみせているだけです。

  次を"clock"という名前のファイルに入れて下さい。

  ______________________________________________________________________
  #!/bin/bash

  function prompt_command {
  let prompt_x=$COLUMNS-5
  }

  PROMPT_COMMAND=prompt_command

  function clock {
  local       BLUE="\[\033[0;34m\]"
  local        RED="\[\033[0;31m\]"
  local  LIGHT_RED="\[\033[1;31m\]"
  local      WHITE="\[\033[1;37m\]"
  local  NO_COLOUR="\[\033[0m\]"
  case $TERM in
      xterm*)
          TITLEBAR='\[\033]0;\u@\h:\w\007\]'
          ;;
      *)
          TITLEBAR=""
          ;;
  esac

  PS1="${TITLEBAR}\
  \[\033[s\033[1;\$(echo -n \${prompt_x})H\]\
  $BLUE[$LIGHT_RED\$(date +%H%M)$BLUE]\[\033[u\033[1A\]
  $BLUE[$LIGHT_RED\u@\h:\w$BLUE]\
  $WHITE\$$NO_COLOUR "
  PS2='> '
  PS4='+ '
  }
  ______________________________________________________________________

  このプロンプトで行なわれていることは比較的単純で、端末の右上に24時間制
  の時刻が表示されます。(端末のサイズを変えても大丈夫です。)これは、カー
  ソルの位置の記憶と回復をサポートしていない端末エミュレータではうまくい
  きません。そのような端末エミュレータでこれを実行すると、時刻は正確に表
  示されますが、プロンプトは端末の2行目から動きません。

  これらのコードをもっと沢山使った例は、 ``役立たずのエレガントな時刻表
  示プロンプト''にあります。

  5.3.  tput でカーソルを動かす

  Unix での多くのことがそうであるように、同じ結果を得るには、二つ以上の
  方法があります。tput と呼ばれるユーティリティでもスクリーン上でカーソ
  ルを動かせます。tput はカーソル操作では ANSI よりも柔軟性が低く、画面
  上の指定した座標に動かすことができるだけで、現在の位置から相対的に動か
  すことはできません。私は"tput"を使いませんので、これ以上詳しくは説明し
  ません。"man tput"とすれば私の知っていることが分かります。

  6.  特別な文字: 8進数エスケープシーケンス

  キーボードから入力できる文字以外にも、スクリーン上に表示できる文字は沢
  山あります。あなたがどんなフォントを使っているのかを確認するためのスク
  リプトを作ってみましたので、使ってみて下さい。このような文字を使うため
  に必要な主なコマンドは"echo -e"です。"-e"スイッチにより、echo はバック
  スラッシュでエスケープされた文字を解釈するようになります。8進
  数200-400で表示されるのは、標準の Linux フォントと VGA フォントでは非
  常に異なっています。これらのエスケープシーケンスがあなたの端末でおかし
  な結果を表示するかもしれませんので、注意して下さい。そうなることを防ぐ
  ようにはしてありません。Bashprompt でよく用いられている(Word Perfect
  でなじみになった)罫線や四角の文字は、 8進数260から337にあります。

  ______________________________________________________________________
  #!/bin/bash

  #   Script: escgen

  function usage {
     echo -e "\033[1;34mescgen\033[0m <lower_octal_value> [<higher_octal_value>]"
     echo "   8進数エスケープシーケンスジェネレーター:下限の値から上限の値までの"
     echo "   すべての8進数エスケープシーケンスを表示します。もし、2番目の上限の"
     echo "   値が与えられなければ、8個の文字が表示されます。"
     echo "   1998 - Giles Orr, no warranty."
     exit 1
  }

  if [ "$#" -eq "0" ]
  then
     echo -e "\033[1;31mPlease supply one or two values.\033[0m"
     usage
  fi
  let lower_val=${1}
  if [ "$#" -eq "1" ]
  then
     #   もし上限値が与えられない場合は、8個にする。
     upper_val=$(echo -e "obase=8 \n ibase=8 \n $lower_val+10 \n quit" | bc)
  else
     let upper_val=${2}
  fi
  if [ "$#" -gt "2" ]
  then
     echo -e "\033[1;31mPlease supply two values.\033[0m"
     echo
     usage
  fi
  if [ "${lower_val}" -gt "${upper_val}" ]
  then
     echo -e "\033[1;31m${lower_val} is larger than ${upper_val}."
     echo
     usage
  fi
  if [ "${upper_val}" -gt "777" ]
     then
     echo -e "\033[1;31mValues cannot exceed 777.\033[0m"
     echo
     usage
  fi

  let i=$lower_val
  let line_count=1
  let limit=$upper_val
  while [ "$i" -lt "$limit" ]
  do
     octal_escape="\\$i"
     echo -en "$i:'$octal_escape' "
     if [ "$line_count" -gt "7" ]
     then
        echo
        #   Put a hard return in.
        let line_count=0
     fi
     let i=$(echo -e "obase=8 \n ibase=8 \n $i+1 \n quit" | bc)
     let line_count=$line_count+1
  done
  echo
  ______________________________________________________________________

  xfd を使って X フォントに含まれるすべての文字を表示することもできま
  す。コマンドは、"xfd -fn <fontname>"です。ある文字の上でクリックする
  と、その8進法での値を含め、その文字に関する様々な情報が得られます。上
  のスクリプトは、コンソール上で現在のフォント名が分からない時に役に立つ
  でしょう。

  7.  Bash Promptパッケージ

  7.1.  入手方法

  Bash Prompt パッケージは、http://bash.current.nuで入手可能です。Rob
  Current (別名BadLandZ) を中心とした人たちの作品です。パッケージはまだ
  初期ベータ版の段階ですが、様々なプロンプト(やテーマ)を(PS1文字列を
  /.bash_profile や  /.bashrc にいれることにより)ログインシェルやサブ
  シェルで使うことを可能にしてくれます。多くのテーマは拡張 VGA 文字セッ
  トを使っていますので、(多くのシステムではデフォルトにはなっていません
  が) VGA フォントでないとうまく表示されません。

  7.2.  Xterm のフォントを変える

  Bash Prompt パッケージの多くの魅力的なプロンプトを使うには、プロンプト
  が想定している文字セットに対応したフォントをインストールする必要があり
  ます。これは VGA フォントと呼ばれていますが、これと Linux に通常ついて
  くるフォントとの違いがよく分かりません。明らかに文字セットは違っていま
  すが。標準の Xterm フォントは、拡張されたアルファベットを持っており、
  アクセントのついた文字を含んでいます。VGA フォントではこのような文字を
  四角や点や線などの図形文字に変えています。これについて詳しく説明できる
  方は私にメールしてください。ここに説明を入れます。

  これらのフォントを入手してインストールするにはちょっと手間がかかりま
  す。まずフォントを入手します。これらが .pcf か .pcf.gz になっているこ
  とを確認してください。もし .bdf になっていたら、bdftopcf コマンドを研
  究してください (man ページを読んで下さい)。.pcf や .pcf.gz ファイルを
  /usr/X11R6/lib/X11/fonts/misc ディレクトリに入れます(RedHat 5.1 や
  Slackware 3.4 ではこうなっていますが、他の Linux ディストリビューショ
  ンでは違うかもしれません)。そのディレクトリに cd し、mkfontdir コマン
  ドを実行します。次に xset fp rehash を実行します。同じディレクトリにあ
  る fonts.alias ファイルを見て、フォントの別名を短く定義するのもいいで
  しょう。

  新しいフォントを使うには適切に Xterm を起動する必要があります。man ペ
  ージをみたり、xterm --help としてみてください。通常次のように起動しま
  す。

       xterm -font <fontname>

  または

       xterm -fn <fontname> -fb <fontname-bold>
       Eterm -f <fontname>
       rxvt -fn <fontname>

  VGA フォントは、
  http://home.earthlink.net/~us5zahns/enl/ansifont.htmlの Stumpy's ANSI
  Fontsページをみてください。(このページはこの文書を書くのに大いに参照さ
  せてもらいました)

  8.  プロンプトを変える

  8.1.  プロンプトを変える、後で

  この HOWTO での説明で、環境変数 PS1 の作り方や、そのような PS1 や PS2
  を  /.bashrc で呼べる関数にいれたり、bashprompt パッケージのテーマとし
  ていれる方法を示してきました。

  bashprompt パッケージを使うのに、bashprompt -iとやれば登録されているテ
  ーマの一覧が出てきます。ログインシェルのプロンプトを設定するには
  bashprompt -l themenameとします。bashprompt は、 /.bash_profile に必要
  なテーマを設定します。サブシェル用に設定するには、 bashprompt -s
  themenameとすると、 /.bashrc が変更されます。

  ``PS? 文字列の設定を永続させる''の章には、 /.bashrcに PS? 文字列を置く
  ことの重要性が書かれていますので、参照して下さい。

  8.2.  プロンプトを変える、今すぐ

  現在の端末のプロンプトを変えるには、上の elite 関数の例を使えば、
  source eliteの後、eliteとします(eliteファイルが現ディレクトリにあると
  して)。これは結構手間がかかります。環境にも elite関数が保存されてし
  まっていますが、これはunset eliteで解放することができます。シェルスク
  リプトで処理するのがいいと思うでしょうが、ここではうまくいきません。ス
  クリプトでは現在の環境を変えることができないからです。スクリプトの動い
  ているサブシェルの環境を変えるだけです。スクリプトが終了すると、サブ
  シェルも終了し、スクリプトによって変化した環境は失われます。現在のシェ
  ルの環境変数を変えるには、環境関数を用いる必要があります。 bashprompt
  パッケージでは、callbashprompt という関数が環境に呼び込まれます。これ
  についてのドキュメントはありませんが、この関数を使うとその場で
  bashprompt のテーマをロードすることができます。インストールされたテー
  マディレクトリに探しにいきますので、あなたが使いたいテーマファイルはこ
  のディレクトリにいれておかなければなりません。ついで、関数を解析し、実
  行し、メモリを解放します。環境領域はふくらんでいきません。
  callbashprompt はこのような使われ方を想定していませんし、エラーチェッ
  クも行ないませんが、そのことだけ覚えておけばうまくいきます。

  9.  動的にプロンプトの色を変える

  9.1.  どうすれば可能か

  これは魅力的なプロンプトというよりは、動的にプロンプトを変えるにはこう
  すれば可能であるという例示です。この例では、ホスト名がシステム負荷に応
  じて色を変えます(警告になります)。

  ______________________________________________________________________
  #!/bin/bash
  #   "hostloadcolour" - 17 October 98, by Giles
  #
  #   この例は、プロンプトのホスト名を負荷の値によって変えます。

  # THRESHOLD_LOAD は、プロンプトの色を COLOUR_LOW から COLOUR_HIGH に
  # 変える1分間の負荷量(の100倍)を示します。
  THRESHOLD_LOAD=200
  COLOUR_LOW='1;34'
            # ライトブルー
  COLOUR_HIGH='1;31'
             # ライトレッド

  function prompt_command {
  ONE=$(uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\)/\1/" -e "s/ //g")
  #   bcのscaleは、乗算には適用されず、除算に適用されるようです。
  ONEHUNDRED=$(echo -e "scale=0 \n $ONE/0.01 \nquit \n" | bc)
  if [ $ONEHUNDRED -gt $THRESHOLD_LOAD ]
  then
      HOST_COLOUR=$COLOUR_HIGH
          # ライトレッド
  else
      HOST_COLOUR=$COLOUR_LOW
          # ライトブルー
  fi
  }

  function hostloadcolour {

  PROMPT_COMMAND=prompt_command
  PS1="[$(date +%H%M)][\u@\[\033[\$(echo -n \$HOST_COLOUR)m\]\h\[\033[0;37m\]:\w]$ "
  }
  ______________________________________________________________________

  好みのエディタを使って、これを hostloadcolour というファイルに保存しま
  す。 Bashprompt パッケージがインストールされているなら、これはテーマ
  ファイルになります。もしインストールしていないなら、source
  hostloadcolour に続いて、hostloadcolourとします。どちらにしても
  prompt_command があなたの環境の関数になります。コードをみると、
  色($COLOUR_HIGHと$COLOUR_LOW) は色コードの一部つま
  り"\[\033[1;34m\]"(こうしたかったのですが)ではなく "1;34"で定義されて
  いることに気づくでしょう。完全な色コードを使いたかったのですが、動きま
  せんでした。どうしたらいいか分かったら教えてください。

  10.  プロンプトの例

  10.1.  「軽量」プロンプト

  ______________________________________________________________________

  function proml {
  local BLUE="\[\033[0;34m\]"
  local RED="\[\033[0;31m\]"
  local LIGHT_RED="\[\033[1;31m\]"
  local WHITE="\[\033[1;37m\]"
  local LIGHT_GRAY="\[\033[0;37m\]"
  case $TERM in
      xterm*)
          TITLEBAR='\[\033]0;\u@\h:\w\007\]'
          ;;
      *)
          TITLEBAR=""
          ;;
  esac

  PS1="${TITLEBAR}\
  $BLUE[$RED\$(date +%H%M)$BLUE]\
  $BLUE[$LIGHT_RED\u@\h:\w$BLUE]\
  $WHITE\$$LIGHT_GRAY "
  PS2='> '
  PS4='+ '
  }
  ______________________________________________________________________

  10.2.  Bashpromptからelite

  VGA フォントが必要です。

  ______________________________________________________________________

  # Created by KrON from windowmaker on IRC
  # Changed by Spidey 08/06
  function elite {
  PS1="\[\033[31m\]\332\304\[\033[34m\](\[\033[31m\]\u\[\033[34m\]@\[\033[31m\]\h\
  \[\033[34m\])\[\033[31m\]-\[\033[34m\](\[\033[31m\]\$(date +%I:%M%P)\
  \[\033[34m\]-:-\[\033[31m\]\$(date +%m)\[\033[34m\033[31m\]/\$(date +%d)\
  \[\033[34m\])\[\033[31m\]\304-\[\033[34m]\\371\[\033[31m\]-\371\371\
  \[\033[34m\]\372\n\[\033[31m\]\300\304\[\033[34m\](\[\033[31m\]\W\[\033[34m\])\
  \[\033[31m\]\304\371\[\033[34m\]\372\[\033[00m\]"
  PS2="> "
  }
  ______________________________________________________________________

  10.3.  「パワーユーザー」プロンプト

  私が実際に使っているプロンプトです。シングルユーザーの
  PentiumII-400MHz でもプロンプト表示の遅れが出ますので、マルチユーザー
  の Pentium-100MHz で使うのはやめておいた方が...。実際に使うというより
  は、考え方の例として見てください。

  ______________________________________________________________________
  #!/bin/bash
  #----------------------------------------------------------------------
  #       POWER USER PROMPT "pprom2"
  #----------------------------------------------------------------------
  #
  #   Created August 98, Last Modified 9 November 98 by Giles
  #
  #   問題:負荷が下がった時 "1.35down-.08" となるので、- をとる必要がある。
  #   - $PWD の長さを30文字までとし、超えた部分は右を切り捨てている。

  function prompt_command
  {
  #   変数 TotalMeg は現ディレクトリの可視ファイルのサイズの合計
  local TotalBytes=0
  for Bytes in $(ls -l | grep "^-" | cut -c30-41)
  do
      let TotalBytes=$TotalBytes+$Bytes
  done
  TotalMeg=$(echo -e "scale=3 \nx=$TotalBytes/1048576\n if (x<1) {print \"0\"} \n print x \nquit" | bc)

  #      uptime コマンドにより、負荷の差分を計算。
  #      uptime は、1分、5分、15分の平均負荷を示す。
  #
  local one=$(uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\)/\1/" -e "s/ //g")
  local five=$(uptime | sed -e "s/.*load average: \(.*\...\), \(.*\...\), \(.*\...\).*/\2/" -e "s/ //g")
  local diff1_5=$(echo -e "scale = scale ($one) \nx=$one - $five\n if (x>0) {print \"up\"} else {print \"down\"}\n print x \nquit \n" | bc)
  loaddiff="$(echo -n "${one}${diff1_5}")"

  #   可視ファイルの数を数える
  let files=$(ls -l | grep "^-" | wc -l | tr -d " ")
  let hiddenfiles=$(ls -l -d .* | grep "^-" | wc -l | tr -d " ")
  let executables=$(ls -l | grep ^-..x | wc -l | tr -d " ")
  let directories=$(ls -l | grep "^d" | wc -l | tr -d " ")
  let hiddendirectories=$(ls -l -d .* | grep "^d" | wc -l | tr -d " ")-2
  let linktemp=$(ls -l | grep "^l" | wc -l | tr -d " ")
  if [ "$linktemp" -eq "0" ]
  then
      links=""
  else
      links=" ${linktemp}l"
  fi
  unset linktemp
  let devicetemp=$(ls -l | grep "^[bc]" | wc -l | tr -d " ")
  if [ "$devicetemp" -eq "0" ]
  then
      devices=""
  else
      devices=" ${devicetemp}bc"
  fi
  unset devicetemp

  }

  PROMPT_COMMAND=prompt_command

  function pprom2 {

  local        BLUE="\[\033[0;34m\]"
  local  LIGHT_GRAY="\[\033[0;37m\]"
  local LIGHT_GREEN="\[\033[1;32m\]"
  local  LIGHT_BLUE="\[\033[1;34m\]"
  local  LIGHT_CYAN="\[\033[1;36m\]"
  local      YELLOW="\[\033[1;33m\]"
  local       WHITE="\[\033[1;37m\]"
  local         RED="\[\033[0;31m\]"
  case $TERM in
      xterm*)
          TITLEBAR='\[\033]0;\u@\h:\w\007\]'
          ;;
      *)
          TITLEBAR=""
          ;;
  esac

  PS1="$TITLEBAR\
  $BLUE[$RED\$(date +%H%M)$BLUE]\
  $BLUE[$RED\u@\h$BLUE]\
  $BLUE[\
  $LIGHT_GRAY\${files}.\${hiddenfiles}-\
  $LIGHT_GREEN\${executables}x \
  $LIGHT_GRAY(\${TotalMeg}Mb) \
  $LIGHT_BLUE\${directories}.\
  \${hiddendirectories}d\
  $LIGHT_CYAN\${links}\
  $YELLOW\${devices}\
  $BLUE]\
  $BLUE[${WHITE}\${loaddiff}$BLUE]\
  $BLUE[\
  $WHITE\$(ps ax | wc -l | sed -e \"s: ::g\")proc\
  $BLUE]\
  \n\
  $BLUE[$RED\$PWD$BLUE]\
  $WHITE\$\
  \
  $LIGHT_GRAY "
  PS2='> '
  PS4='+ '
  }
  ______________________________________________________________________

  10.4.  端末幅のプロンプト

  プロンプトに $PWD が含まれると、プロンプトの長さが変わるとなげく友人が
  いたので、プロンプトの長さがちょうど端末の幅になるプロンプトを書いてみ
  ました。

  ______________________________________________________________________
  #!/bin/bash

  #   端末幅のプロンプト
  #      by Giles - created 2 November 98
  #                 last modified 9 November 98
  #
  #   ここで考えたのは、2行からなるプロンプトの1行目が端末の幅になるように
  #   することです。そうするために、テキストの文字数を数え、幅に合うように
  #   $PWD を補ったり、右を切り詰めたりします。
  #
  #   - もっと洗練させる必要がありますが、とりあえず動きます。
  #   - ホスト名は毎回さがす必要がありません。変化しませんから。
  #   - ユーザー名はどうだろう? 変わるかなあ?
  #   - prompt_command で作られるテキスト変数は局所変数ではいけない。
  #     PS1 に保存される必要があるから。

  function prompt_command {

  TERMWIDTH=${COLUMNS}

  #   プロンプト幅を計算

  hostnam=$(echo -n $HOSTNAME | sed -e "s/[\.].*//")
  let hostsize=$(echo -n $hostnam | wc -c | tr -d " ")
  #   "whoami" と "pwd" の最後は改行になっている。
  usernam=$(whoami)
  let usersize=$(echo -n $usernam | wc -c | tr -d " ")
  newPWD="${PWD}"
  let pwdsize=$(echo -n ${newPWD} | wc -c | tr -d " ")
  #   アクセサリをつけていく
  let promptsize=$(echo -n "--(${usernam}@${hostnam})---(${PWD})--" \
                   | wc -c | tr -d " ")
  let fillsize=${TERMWIDTH}-${promptsize}
  fill=""
  while [ "$fillsize" -gt "0" ]
  do
      fill="${fill}-"
          let fillsize=${fillsize}-1
  done

  if [ "$fillsize" -lt "0" ]
  then
      let cut=((${fillsize})*(-1))+3
      sedvar=""
      while [ "$cut" -gt "0" ]
      do
          sedvar="${sedvar}."
      let cut=${cut}-1
      done
      newPWD="...$(echo -n $PWD | sed -e "s/\(^${sedvar}\)\(.*\)/\2/")"
  fi
  }

  PROMPT_COMMAND=prompt_command

  function termwide {

  local GRAY="\[\033[1;30m\]"
  local LIGHT_GRAY="\[\033[0;37m\]"
  local WHITE="\[\033[1;37m\]"

  local LIGHT_BLUE="\[\033[1;34m\]"
  local YELLOW="\[\033[1;33m\]"

  case $TERM in
      xterm*)
          TITLEBAR='\[\033]0;\u@\h:\w\007\]'
          ;;
      *)
          TITLEBAR=""
          ;;
  esac

  PS1="$TITLEBAR\
  $YELLOW-$LIGHT_BLUE-(\
  $YELLOW\${usernam}$LIGHT_BLUE@$YELLOW\${hostnam}\
  ${LIGHT_BLUE})-${YELLOW}-\${fill}${LIGHT_BLUE}-(\
  $YELLOW\${newPWD}\
  $LIGHT_BLUE)-$YELLOW-\
  \n\
  $YELLOW-$LIGHT_BLUE-(\
  $YELLOW\$(date +%H%M)$LIGHT_BLUE:$YELLOW\$(date \"+%a,%d %b %y\")\
  $LIGHT_BLUE:$WHITE\$$LIGHT_BLUE)-\
  $YELLOW-\
  $LIGHT_GRAY "

  PS2="$LIGHT_BLUE-$YELLOW-$YELLOW-$LIGHT_GRAY "

  }
  ______________________________________________________________________

  10.5.  役立たずのエレガントな時刻表示プロンプト

  これは私が作ったプロンプトの中で、おそらくもっとも魅力的な(もっとも役
  立たない) ものです。多くのX端末エミュレータは、カーソル位置の記憶と復
  旧を実現していませんので、時刻を右上に置くためにカーソルを端末の最下行
  に固定しています。このプロンプトは、上の端末幅のプロンプトのアイディア
  を使っており、画面の右端にプロンプトから時刻表示のところまで直線を引い
  ています。VGA フォントが必要です。

  注意: ここでは変な置換が使われていますので、SGML から他のフォーマット
  に変えた時にきちんと表示されないかもしれません。\304の文字を置換する必
  要がありました。通常は"\304"でいいのですが、ここではこのような置換をす
  ることが必要でした。

  ______________________________________________________________________
  #!/bin/bash

  #   このプロンプトは VGA フォントを必要とする。プロンプトは端末の一番下の行に
  #   端末幅一杯に表示され、画面の右端に直線を表示し、右上の時刻表示につながっ
  #   ている。

  function prompt_command {
  #   Calculate the width of the prompt:
  hostnam=$(echo -n $HOSTNAME | sed -e "s/[\.].*//")
  #   "whoami"と"pwd"は最後に改行を含んでいる。
  usernam=$(whoami)
  newPWD="${PWD}"
  #   すべてのアクセサリを以下に加える。
  let promptsize=$(echo -n "--(${usernam}@${hostnam})---(${PWD})-----" \
                   | wc -c | tr -d " ")
  #   user@host と PWD の間にどれだけ加えればいいか(PWD から切り取ればよいか)を
  #   計算する。
  let fillsize=${COLUMNS}-${promptsize}
  fill=""
  #   プロンプトが端末幅より短い場合には、埋め草を作る。
  while [ "$fillsize" -gt "0" ]
  do
     fill="${fill}"
     # A ウムラウト(VGA フォントでは長い横線)は\304ですが、Bash では置換は
     # 一種類しか行なわれず、ここでは $fill をプロンプトに埋め込むことな
     # ので、このように変えました。
     let fillsize=${fillsize}-1
  done
  #   プロンプトが端末幅より長過ぎるようなら、PWD の右を切り捨てます。
  if [ "$fillsize" -lt "0" ]
  then
     let cutt=3-${fillsize}
     sedvar=""
     while [ "$cutt" -gt "0" ]
     do
        sedvar="${sedvar}."
        let cutt=${cutt}-1
     done
     newPWD="...$(echo -n $PWD | sed -e "s/\(^${sedvar}\)\(.*\)/\2/")"
  fi
  #
  #   時刻と端末の右端に表示するバーを作ります。
  #
  local LIGHT_BLUE="\033[1;34m"
  local     YELLOW="\033[1;33m"
  #   時刻を表示するカーソルの位置を決めます。
  echo -en "\033[2;$((${COLUMNS}-9))H"
  echo -en "$LIGHT_BLUE($YELLOW$(date +%H%M)$LIGHT_BLUE)\304$YELLOW\304\304\277"
  local i=${LINES}
  echo -en "\033[2;${COLUMNS}H"
  #   縦線を端末の脇に表示します。
  while [ $i -ge 4 ]
  do
     echo -en "\033[$(($i-1));${COLUMNS}H\263"
     let i=$i-1
  done

  let prompt_line=${LINES}-1
  #   Bashの数式表現($(()))の中では、\${LINES}がうまく機能しないようなので
  }

  PROMPT_COMMAND=prompt_command

  function clock3 {
  local LIGHT_BLUE="\[\033[1;34m\]"
  local     YELLOW="\[\033[1;33m\]"
  local      WHITE="\[\033[1;37m\]"
  local LIGHT_GRAY="\[\033[0;37m\]"
  local  NO_COLOUR="\[\033[0m\]"

  case $TERM in
      xterm*)
          TITLEBAR='\[\033]0;\u@\h:\w\007\]'
          ;;
      *)
          TITLEBAR=""
          ;;
  esac

  PS1="$TITLEBAR\
  \[\033[\${prompt_line};0H\]
  $YELLOW\332$LIGHT_BLUE\304(\
  $YELLOW\${usernam}$LIGHT_BLUE@$YELLOW\${hostnam}\
  ${LIGHT_BLUE})\304${YELLOW}\304\${fill}${LIGHT_BLUE}\304(\
  $YELLOW\${newPWD}\
  $LIGHT_BLUE)\304$YELLOW\304\304\304\331\
  \n\
  $YELLOW\300$LIGHT_BLUE\304(\
  $YELLOW\$(date \"+%a,%d %b %y\")\
  $LIGHT_BLUE:$WHITE\$$LIGHT_BLUE)\304\
  $YELLOW\304\
  $LIGHT_GRAY "

  PS2="$LIGHT_BLUE\304$YELLOW\304$YELLOW\304$NO_COLOUR "

  }
  ______________________________________________________________________

  翻訳     遠藤 明 akendo@t3.rim.or.jp

  校正協力 yuri aisaka <ayqw@mail2.alpha-net.or.jp> HASEGAWA Yasushi
  <yaz-hase@qb3.so-net.ne.jp>

