コマンドの文法

シェルはコマンドを一行ずつ読み込んで解釈し、実行します。一行に複数のコマンドがある場合は、それら全てを解釈してから実行します。一つのコマンドが複数行にまたがっている場合は、そのコマンドを解釈し終えるのに必要なだけ後続の行が読み込まれます。コマンドを正しく解釈できない場合は、文法エラーとなり、コマンドは実行されません。

非対話モードで文法エラーが発生した時は、シェルはコマンドの読み込みを中止するため、それ以降のコマンドは一切読み込まれません。

トークンの解析と予約語

コマンドは、いくつかのトークンによって構成されます。トークンとは、シェルの文法における一つ一つの単語のことを言います。トークンは原則として空白 (空白文字またはタブ文字) によって区切られます。ただしコマンド置換などに含まれる空白はトークンの区切りとは見なしません。

以下の記号は、シェルの文法において特別な意味を持っています。これらの記号も多くの場合他の通常のトークンの区切りとなります。

; & | < > ( )

以下の記号はトークンの区切りにはなりませんが、文法上特別な意味を持っています。

$ ` \ " ' * ? [ # ~ = %

以下のトークンは特定の場面において予約語と見なされます。予約語は複合コマンドなどを構成する一部となります。

! { } case do done elif else esac fi for if in then until while

これらのトークンは以下の場面において予約語となります。

トークンが # で始まる場合、その # から行末まではコメントと見なされます。コマンドの解釈においてコメントは完全に無視されます。

クォート

空白や上記の区切り記号・予約語などを通常の文字と同じように扱うには、適切な引用符でクォートする必要があります。引用符として、バックスラッシュ・一重引用符・二重引用符の三種類が使えます。

エイリアス

コマンドを構成する各トークンは、それが予め登録されたエイリアスの名前に一致するかどうか調べられます。一致するものがあれば、そのトークンはそのエイリアスの内容に置き換えられて、その後コマンドの解析が続けられます。これをエイリアス置換といいます。

エイリアスの名前に引用符を含めることはできないので、引用符を含むトークンはエイリアス置換されません。また、予約語もエイリアス置換されません。

エイリアスには通常のエイリアスとグローバルエイリアスの二種類があります。通常のエイリアスは、コマンドの最初のトークンにのみ一致します。グローバルエイリアスはコマンド内の全てのトークンが一致の対象です。グローバルエイリアスは POSIX 規格にはない拡張機能です。

エイリアス置換の結果がさらに別のエイリアスに一致して置換される場合もあります。しかし、同じエイリアスに再び一致することはありません。

単純コマンド

最初のトークンが予約語でないコマンドは、単純コマンドです。単純コマンドはコマンドの検索と実行のしかたに従って実行されます。

単純コマンドの初めのトークンが 名前= の形式になっている場合は、それは変数代入と見なされます。ただしここでの名前は、一文字以上のアルファベット・数字または下線 (_) で、かつ最初が数字でないものです。変数代入ではない最初のトークンはコマンドの名前と解釈されます。それ以降のトークンは (たとえ変数代入の形式をしていたとしても) コマンドの引数と解釈されます。

全てのトークンが変数代入の形式ならば、変数の代入だけが行われ、コマンドは実行されません。

パイプライン

パイプラインは、一つ以上のコマンドを記号 | で繋いだものです。

パイプラインの実行は、パイプラインに含まれる各コマンドをそれぞれ独立したサブシェルで同時に実行することで行われます。この時、各コマンドの標準出力は次のコマンドの標準入力にパイプで受け渡されます。最初のコマンドの標準入力と最後のコマンドの標準出力は元のままです。パイプライン内のコマンドの実行が終わると、パイプラインの実行が終わります。最後のコマンドの終了ステータスがパイプラインの終了ステータスになります。

パイプラインの先頭には、記号 ! を付けることができます。この場合、パイプラインの終了ステータスが逆転します。つまり、最後のコマンドの終了ステータスが 0 のときはパイプラインの終了ステータスは 1 になり、それ以外の場合は 0 になります。

注: 最後のコマンドの終了ステータスがパイプラインの終了ステータスになるため、パイプラインの実行が終了するのは少なくとも最後のコマンドの実行が終了した後です。しかしそのとき他のコマンドの実行が終了しているとは限りません。また、最後のコマンドの実行が終了したらすぐにパイプラインの実行が終了するとも限りません。(シェルは、他のコマンドの実行が終わるまで待つ場合があります)

注: POSIX 規格では、パイプライン内の各コマンドはサブシェルではなく現在のコマンド実行環境で実行してもよいことになっています。

And/or リスト

And/or リストは一つ以上のパイプラインを記号 && または || で繋いだものです。

And/or リストの実行は、and/or リストに含まれる各パイプラインを条件付きで実行することで行われます。最初のパイプラインは常に実行されます。それ以降のパイプラインの実行は、前のパイプラインの終了ステータスによります。

最後に実行したパイプラインの終了ステータスが and/or リストの終了ステータスになります。

複合コマンド

複合コマンドは、より複雑なプログラムの制御を行う手段を提供します。

グルーピング

グルーピングを使うと、複数のコマンドを一つのコマンドとして扱うことができます。

通常のグルーピングの構文
{ コマンド...; }
サブシェルのグルーピングの構文
(コマンド...)

{} は予約語なので、他のコマンドのトークンとくっつけて書いてはいけません。一方 () は特殊な区切り記号と見なされるので、他のトークンとくっつけて書くことができます。

通常のグルーピング構文 ({} で囲む) では、コマンドは (他のコマンドと同様に) 現在のコマンド実行環境で実行されます。サブシェルのグルーピング構文 (() で囲む) では、括弧内のコマンドは新たなサブシェルで実行されます。

If 文

If 文は条件分岐を行います。分岐の複雑さに応じていくつか構文のバリエーションがあります。

If 文の基本構文
if コマンド...; then コマンド...; fi
Else がある場合
if コマンド...; then コマンド...; else コマンド...; fi
Elif がある場合
if コマンド...; then コマンド...; elif コマンド...; then コマンド...; fi
Elif と else がある場合
if コマンド...; then コマンド...; elif コマンド...; then コマンド...; else コマンド...; fi

どの構文の場合でも、ifthen の間にあるコマンドがまず実行されます。コマンドの終了ステータスが 0 ならば、条件が真であると見なされて thenfi (あるいは elseelif) の間にあるコマンドが実行され、if 文の実行はそれで終了します。終了ステータスが 0 でなければ、条件が偽であると見なされます。ここで elseelif もなければ、if 文の実行はこれで終わりです。else がある場合は、elsefi の間のコマンドが実行されます。elif がある場合は、elifthen の間にあるコマンドが実行され、その終了ステータスが 0 であるかどうか判定されます。その後は先程と同様に条件分岐を行います。

elifthen は一つの if 文内に複数あっても構いません。

If 文の終了ステータスは、どれかの条件が真であった場合はそれに対応して実行された then の後のコマンドの終了ステータスです。どの条件も偽であった場合は、else の後のコマンドの終了ステータスです (else がない場合は 0)。

While/until ループ

For ループ

Case 文

コマンドの区切りと非同期コマンド

関数定義