シェルとは、ユーザーから入力されたコマンドを解釈し、 プログラムを起動するアプリケーションです。 他の OS で機能的に似た役割を持つものとして、 Windows95/98では Explorer、Macintosh(MAC)では finder があります。 しかし、イメージとしては Windows95/98 の DOS プロンプトや、 WindowsNT のコマンドプロンプトの方が近いでしょう。
通常、シェルは login シェルとして、 各ユーザがログインする度に起動され、ログアウトの際に終了します。 ログインすると、端末の上に、例えば "samson$" と表示されますが、 これがシェルが発している「プロンプト」(ユーザへコマンドの入力を促す記号)です。
UNIX の内部構造をみると、核となる部分はカーネル(Kernel)と呼ばれ、 マルチタスクやファイルシステム、仮想記憶、入出力など、 OS にとって重要な機能を司っています。 ユーザーはカーネルを直接操るのではなく、 あらかじめ用意されたインターフェイス(窓口)を通して、 カーネルに対してコマンドの実行を要求します。 このインターフェイスの部分がシェルであり、 つまりシェルはユーザとカーネルの仲立ちをしているプログラムであると言えるでしょう。
シェルには大きく分けて3つの役割があります。
主要なシェルには以下のようなものがあります。
$ set
$ finger username
$ grep '^username:' /etc/passwd
$ chsh (または ypchsh)
次にログインするときに、変更したシェルが起動されます。 (管理者の設定により無理な場合があります)
多くのシェルは、ls や kterm などの独立したコマンドを実行するだけでなく、 あらかじめシェルのプログラムに組み込まれているコマンドを幾つか持っています。 このようなコマンドは"組み込みコマンド"と呼ばれ、以下のようなものがあります。
echo, set, unset, alias, history, cd, ...
help コマンドを利用すると、これら組み込みコマンドの、簡単な説明を得られます。
$ help
$ help [コマンド名]
bashは、シェル自身の動作を定義する変数を持っています。 この、シェルが内部で保持している変数を、"シェル変数"と言います。 シェルスクリプトや、コマンドの入力の際に、 値を一時的に格納して後で再利用できるようにするための変数でもあります。 後述する環境変数と違い、シェル以外のプログラムからは参照できません。
基本的に、変数名をつける際は、好きなようにつけて構わないのですが、すでに定義され ている変数とは重ならないように指定した方が無難です。
例として、プロンプトの表示を変えてみましょう。 プロンプトの表示は、シェル変数"PS1"を用いて設定することが出来ます。
| $ PS1="\u% " inex% inex% PS1="\d$ " Fri Nov 26$ Fri Nov 26$ PS1="\s-\v\$ " bash-2.01$ | 
シェル変数はシェルの中だけで使われる変数ですが、 こちらは、アプリケーションやコマンドなどの動作を統一的に制御するために 、ユーザーが設定する変数です。 代表的なものとしては、USER, HOST, LANG, DISPLAY, PATH, HOME などがあります。
シェル変数・環境変数には、 あらかじめ使い方が決められたものがあり、 変更には注意が必要です。
例として、以下の4つのコマンドを順番に入力してみてください。
| $ export LANG=C $ man man $ export LANG=ja_JP.ujis $ man man | 
これを実際に試してみると、 一度目の man man と二度目の man man で出力される結果が違うのが、 確認できると思います。 環境変数とはこのように、 あらかじめ設定していた文字列によってプログラムの動作を規定する為のものです。 (プログラム側で対応していない場合は効果ありません)
コマンド入力の際に、 複数のファイル名を「ある規則にしたがってまとめて表す」という試みのために用いられる文字のことを、 "メタキャラクタ"(ワイルドカード)と言います。 メタキャラクタを用いると、タイプする文字数を減らすことができるので、 効率的に入力が行えます。
| メタキャラクタ | 意味 | 
|---|---|
| * | 任意の文字列を表す。 | 
| ? | 任意の1文字を表す。?? は任意の2文字になる。 | 
| [ ] | [ ] 内に含まれる文字にマッチする。 例えば [a-c]* は abc のいすれかで始まる任意の文字列を表す。 | 
| { } | { }内に含まれる文字列にマッチする。 例えば test.{pl,gif,f} は、test.pl test.gif test.f と入力したことになる。 | 
あるコマンドに対して、別名をつけたいときに用います。
alias 別名=コマンド名
alias 別名='オプション付きのコマンド名'
お薦め: rm -i を rm と変更
ジョブ(Job)とは、ユーザがコンピュータに行なわせる仕事の単位です。
似た意味を持つ言葉に、タスクとプロセスがありますが、 この2つは共にマルチプログラミングの目的で、 コンピュータがCPU(中央演算処理装置)に行わせる仕事の単位です。 ジョブは、複数のジョブステップから構成されることがありますから、 ジョブとタスクは一致するとは限りません。
bash には、1つのシェルで複数のジョブを切替えながら、 並行して作業を行う機能があります。これをジョブ制御と呼びます。
上記2種のジョブを制御するために、 bash には fg, bg, jobs コマンド、そして & が用意されています。
はじめフォアグランドジョブとして起動されたコマンドを、 バックグランドジョブに変更するには、 (フォアグランドジョブが実行されているために)プロンプトが表示されていない状態の端末で、 Ctrl-z(コントロール・キーを押しながら z キーを押す)として、 ジョブを中断させます。
| $ kterm & $ xclock ^Z [2]+ Stopped xclock | < Ctrl-z を押します > ジョブ番号[2]の xclock が停止しました | 
次に jobs と打ち込み、現在このシェルから実行中のジョブ一覧を表示させます。
| $ jobs [1]- Running kterm & [2]+ Stopped xclock | > ジョブ番号[1]の kterm が実行中です > ジョブ番号[2]の xclock が停止中です | 
xclock より前に kterm が実行されていたので、上のような表示になります。 [ ]の中の数字はジョブの番号を表します。 +は "current job"、- は"previous job"と呼ばれ、 ジョブの切替え対象となる順番を表しています。
bg コマンドを用いると、 フォアグランドジョブをバックグランドジョブに切り替えることが出来ます。 (bg の後に % ジョブ番号と入力)
| $ bg %2 [1]- Running kterm & [2]+ Running xclock & | > ジョブ番号[1]の kterm が実行中です > ジョブ番号[2]の xclock が実行中です | 
逆に、バックグランドジョブをフォアグランドジョブに切り替えるには、 fg コマンドを用います。(ジョブ番号の指定の仕方は、bg コマンドと同様)
| $ fg %1 kterm | 
bash には、途中まで打ち込まれた内容を元に、 ファイルやコマンドを補完する機能が備わっています。 具体的には、目的の文字列を何文字か入力し、Tab キーを押します。 複数候補が存在する場合は、Tab キーを2回押すことで、 その一覧を表示させることが出来ます。 この機能は他にも、シェル変数、ユーザー名、ホスト名なども補完してくれます。
これまで見てきたように、シェルはユーザとコンピュータの橋渡しをして、 ユーザがコマンドを端末から打ち込む毎に、それを解釈し実行します。 一方、[1.2]節で触れたように、 「プログラムが可能である」という、もう一つの面もあります。 この、プログラムとして手続きを書き込んだファイルを 「スクリプト・ファイル」と言います。 スクリプト(script)とは劇の「台本」のことであり、 台本を事前に決めていてそれに沿って行わせるためにこの名前があります。
シェル・プログラミングは通例、B シェルを使って行います*。 具体的にどのようなものか、簡単な例を見てみましょう。
次のような一連の仕事を行うコマンドを作ることを考えます。 (カレントディレクトリは /home/inex/script)
従って、次のようなファイルを書こう。
[スクリプトファイル:sample]#! /bin/shここで、
date
pwd
echo 'Hey!'
$ sh sampleとすると、次のように出力される。
| $ sh sample 1990年9月27日(木) 14:40 /home/inex/script Hey! | 
この場合、B シェル(sh)をわざわざ起動して、 その引数としてファイル名を指定し、 そのファイルを B シェルが解釈して実行しています。
いちいちこのようなことをするのは非能率でもあるので、
$ chmod 744 sampleもしくは
$ chmod u+x sampleとすると、スクリプトのファイル名を入力するだけで実行することができます。
$ sample
この場合、自動的に(自分が使っている login シェル)が、 スクリプトファイルを B シェルに解釈させ実行させています。
引数とは、実行時にそのシェルスクリプトに教えて上げたい追加情報であるとも言えます。
たとえば、コマンド ls は、そのままではカレント・ディレクトリ内のファイルをリストアップしますが、 引数として特定のディレクトリを指定すると、指定されたディレクトリ内のファイルをリストアップします。 これはコマンド ls に、引数として指定したディレクトリについて知りたいんだよ、 と追加情報を与えているわけです。
コマンドやシェルスクリプトに引数を指定することを、"引数を渡す"とも表現します。 シェルスクリプトに渡された引数を処理したい場合は、$1, $2, ... $9 というシェル変数を利用します。
例えば、次のような、引数に渡された単語をそのまま表示するシェルスクリプトを考えてみましょう。
$ script Hello!
#!/bin/sh
echo $1
ここでは、引数の文字を画面に出力するコマンド echo に、シェル変数 $1 を引数として渡しています。 このシェル変数 $1 には、シェルスクリプト script に渡された引数 Hello! が入ります。 結果、画面には Hello! と表示されるでしょう。
引数を参照するシェル変数は9つまで使うことが出来ます。それぞれ、$1, $2, ... $9 です。
シェルスクリプト内でも、シェルで用意されたメタキャラクタを利用することができます。 B シェルのメタキャラクタは以下の通りです。
| メタキャラクタ | 意味 | 
|---|---|
| > | program >file とすると標準出力を file に切り換える。 | 
| 2> | program 2>file とすると標準エラー出力を file に切り換える。 | 
| >> | >>file とすると標準出力を file に追加する。 | 
| < | program <file とすると標準入力として file から読み込む。 | 
| | | program1|program2 とすると program1 の標準出力を program2 につなぐ。 | 
| <<string | ヒア・ドキュメント。string と書かれた行が次に現れるまで、 この後に続く行を標準入力にする。 | 
| * | ファイル名の中の長さ0以上の任意の文字列と一致する。 (file* とすると、filea, fileb, fileabc はもとより file というのも含まれることになるので注意を要する。) | 
| ? | ファイル名の中の任意の1文字と一致する。 | 
| [ccc] | ファイル名の中の ccc のなかの任意の文字と一致する。 0-9,a-z といった範囲指定も許される。 | 
| ; | コマンドの区切り。program1;program2 とすると、 まず program1 が実行され、次に program2 が実行される。 | 
| & | ;と似ている。ただし、program1 の終了を待たない。 | 
| `...` | ... にあるコマンド(群)を実行し、その出力は`...` に置換される。 | 
| (...) | ... のコマンド(群)をサブシェルのなかで実行する。 | 
| {...} | ... のコマンド(群)をカレントシェルのなかで実行する。 | 
| $1, $2, etc | $0...$9 はシェルファイルに対する引数に置換される。 | 
| $var | シェル変数 var の値。 | 
| ${var} | シェル変数 var の値。 テキスト部分と連結されたときの混乱を防ぐために ${var} を用いる。 | 
| \ | エスケープ記号。c がシェルのメタ・キャラクタである場合、 \c は c の特別な意味を打ち消し、単なる文字としての c にする。 | 
| '...' | ... をそのまま取り出す。 | 
| "..." | うちに含まれる $,`...`,\ を解釈した後で ... を取り出す。 | 
| # | 単語の先頭に # があると、その行に書かれた残りの内容はコメントになる。 | 
| var=value | 変数 var への値 value の代入 | 
| p1 && p2 | p1 を実行し、もしうまくいったら p2 を実行する。 | 
| p1 || p2 | p1 を実行し、もしうまくいかなかったら p2 を実行する。 | 
より複雑な処理をこなす場合でも、大抵は次の3つの処理の組み合わせで表現できます。
順序構造は、順番にコマンドを実行するものであるから、特別の制御文は必要ありません。
選択構造には、if 、case を使います。 繰り返し構造には、for 、while 、until を使います。
| if | |
|---|---|
| 書式 | 
    if テストコマンド
        then コマンド1
       [else コマンド2]
    fi
   | 
| 解説 | if 文は if と fi で対になって、いれ子を形成しています。 if に続く「テストコマンド」をまず実行し、 それが「真」(0以外の値)を返したら then に続くコマンドが、 「偽」(0)を返したら else に続くコマンドが実行されます。 else とコマンド2の部分は省略可能です。 また、コマンド1とコマンド2には、 複数のコマンドからなるコマンド列を記述することも出来ます。 if....fi のいれ子は多重に重ねることが出来ます。 if に続くテストコマンドの文と then に続くコマンド1の文は普通改行します。 どうしても1行にまとめて書きたければ、if テストコマンド; then コマンド1 のようにセミコロンを挟みます。 | 
| case | |
|---|---|
| 書式 | 
    case 文字 in
        パターン1)  コマンド1  ;;
        パターン2)  コマンド2  ;;
          ・
          ・
    esac
   | 
| 解説 | 
      パターンには、メタキャラクタ | 
| while, until | |
|---|---|
| 書式 | 
    while コマンド; do
      コマンド
    done
   | 
| 解説 | while は、while の左に書かれたコマンドが真(0以外の値)を返す限り、 do と done の間に書かれたコマンド(列)を実行し続けます。 while の代わりに until と書くと、その左に指定されたコマンドが偽(0)を返す限り、 do と done の間に書かれたコマンド(列)を実行し続けます。 | 
#!/bin/sh
case $# in
    0) echo '引数なし' ;;
    1) echo '引数一つ' ;;
    2) echo '引数二つ' ;;
    *) echo '引数三つ以上' ;;
esac
※ $# は与えられた引数の数を表すシェル変数です。
■引数に指定された複数のファイル名に対し、実在する物のみファイル名を表示する。
#!/bin/sh
while test $# -gt 0
do
    if test -f $1; then
        echo $1
    fi
    shift
done
※ test は、それに続く式を評価して値を返すコマンドです。 与えるオプションに応じて、数値に関するテスト、 ファイルの型に関するテスト、文字列に関するテストを行うことが出来ます。 例えば、test -f [ファイル名]とすると、ファイルが存在すれば真、 存在しなければ偽を返します。
■数字の1から9を表示する。
#!/bin/sh
number=1
while test $number -ne 10
do
    echo $number
    number=`expr $number + 1`
done
※expr コマンドはその引数を1つの式として評価し、
その結果を表示します。これを使うと UNIX で簡単な計算を行い、
シェル・スクリプトの中に算術演算処理を含めることが出来ます。
なお、number の式の右辺はクオーテーション(')ではありません。
注意して下さい。
気になる人は B シェルのメタキャラクタの欄を参照して下さい。
より詳しい情報は man sh として B シェルのマニュアルを参照することで得ることも出来ましょう。 分からないコマンドや単語は、困ってないでどんどん調べようね。
| 最終更新日: 2000/10/26(河野仁之) | Copyright © 2000 inex |