C shell(シーシェル、csh)は、カリフォルニア大学バークレー校の大学院生だったビル・ジョイが1970年代後半に開発したUnixシェルである。1978年にジョイが配布を始めた 2BSD という BSD UNIX のリリースで広く配布されることになった。他にアイデアやコードに貢献した者としては、マイケル・ウベル、エリック・オールマン、マイク・オブライエン、ジム・カルプがいる。UNIX V6 の /bin/sh を元に作られたもので、Bourne shell (UNIX V7) と共通の先祖を持つ。

通常テキストウィンドウ内で動作するコマンドラインインタプリタであり、ユーザーがコマンドを入力するとそれに応じた処理が実行される。またシェルスクリプトと呼ばれるファイルからコマンド群を読み込むこともできる。他のUnixシェルと同様、ファイル名のワイルドカード、パイプ、ヒアドキュメント、コマンド置換、変数、条件分岐やループなどの制御構造をサポートしている。cshが1980年代の他のシェルと異なっていた点は、対話向けの機能と全体的なスタイルである。新機能によって他のシェルよりも容易に素早く使うことができた。言語としての全体的スタイルはC言語によく似ており、Unixユーザーにとっては読みやすかった。

macOS や Red Hat Linux など多くのシステムのcshは実際には改良版のtcshである。tcshの実行ファイルは "csh" と "tcsh" の両方にハードリンクされていて、どちらの名前でも同じ改良版のtcshが呼び出される。

DebianやUbuntuではcshとtcshの2種類のパッケージを用意しており、前者はオリジナルのBSD版csh、後者は改良版のtcshとなっている。両方をインストールした場合、cshとしてどちらを使用するかupdate-alternativesコマンドで選択できる。

tcshには、ファイル名やコマンドの補完機能、Tenexシステムに由来するコマンド行編集があり、名称の先頭の "t" は Tenex に因んでいる。tcshは機能を追加しただけでオリジナルのcshを修正したわけではないので、後方互換を保っていた。当初はジョイが作ったオリジナルのソースツリーからの脇枝だったが、今ではtcshが主な枝となっていて、開発が継続されている。tcshは非常に安定しているが、主に細かいバグ修正のため、およそ1年に1回の頻度で新たなリリースがなされている。

## 設計目標と機能

C shell の主たる設計目標は、C言語に似せることと、対話型利用での改良であった。

### C言語風のスタイル

Unixシステムはほとんど全体がCで書かれているため、C shell の第一の目標はスタイル上システム全体と一貫性のあるコマンド言語とすることだった。キーワード、括弧の利用、組み込みの式の文法、配列サポートなどは全てCの影響を強く受けている。

今ではC言語によく似た文法のスクリプト言語がいくつもあり、それらに比べればcshはそれほどC言語に似ているとは言えない。しかし80年代から90年代にかけて、特にAT&Tでスティーブン・ボーンが開発したshと比べたときの違いは著しいと見られていた。次の例は、C shell の演算子や構文のわかりやすさを示したものである。

| Bourne shell | C shell |
| --- | --- |
| ``` #!/bin/sh if [ $days -gt 365 ] then    echo This is over a year. fi ``` | ``` #!/bin/csh if ( $days > 365 ) then    echo This is over a year. endif ``` |

shには式の文法が存在しない。`[`(角括弧)で囲まれた条件式は、外部のtestというプログラムで評価する必要がある。つまり、shのifコマンドは子プロセスを起動して引数を別のコマンドとして実行させる。その子プロセスが終了したときのリターンコードがゼロならthen節を探し(then節はifとは別の文だが、セミコロンをはさんで一行で書かれることが多い)、入れ子になったブロックを実行する。リターンコードがゼロ以外ならelse節を実行する。testプログラムを "`test`" と "`[`" の両方にハードリンクすることで、角括弧表記の利点が生まれ、testの機能があたかもshの一部であるかのような錯覚を与える。shで制御ブロックの終端にキーワードを逆に綴ったものを置くのは、ALGOL 68 のスタイルを踏襲したものである。

対照的にcshは自前で式を評価でき、高速である。可読性もよいと言われている。演算子や構文の多くはC言語のものをそのまま使っている。キーワードを逆に綴ることもなく、全体としてよりC言語に近いスタイルである。

次の例は、2の1乗から10乗までを計算するスクリプトを比較したものである。

| Bourne shell | C shell |
| --- | --- |
| ``` #!/bin/sh i=2 j=1 while [ $j -le 10 ] do    echo '2 **' $j = $i    i=`expr $i '*' 2`    j=`expr $j + 1` done ``` | ``` #!/bin/csh set i = 2 set j = 1 while ( $j <= 10 )    echo '2 **' $j = $i    @ i *= 2    @ j++ end ``` |

やはりshには式の文法が存在しないため、shのスクリプトはコマンド置換とexprコマンドを使っている。C shell の @ 文(コマンド)は一種の駄洒落であり、"at-sign-ment" すなわち代入文を意味している。

最後の例は、switch文のスタイルの違いを示したものである。

| Bourne shell | C shell |
| --- | --- |
| ``` #!/bin/sh for i in d* do    case $i in       d?) echo $i is short ;;       *) echo $i is long ;;    esac done ``` | ``` #!/bin/csh foreach i ( d* )    switch ( $i )       case d?:          echo $i is short          breaksw       default:          echo $i is long    endsw end ``` |

shのスクリプトでは、"`;;`" で各ケースの終りを示す。通常は空文を許さないため、これはケースの終りを目立たせるためである。

### 対話型利用のための改良点

C shell の第二の設計目標は、対話型利用の改良だった。そのため、ユーザビリティや入力の高速性を追求したいくつかの新機能を導入している。必要な結果を得るのに打ち込まなければならないキーストローク数を減らすことで、高速性を実現している。特に重要なのは、ヒストリとその編集機構、エイリアス、ディレクトリスタック、チルダ記法、cdpath、ジョブコントロール、パスハッシングである。これら新機能は人気となり、多くが他のUnixシェルにも採用された。

## スクリプト言語としての C Shell

C shell は行単位で操作する。各行を字句解析して空白、括弧、パイプやリダイレクトを表す記号、セミコロン、アンパサンド等で区切られた単語の並びとして認識する。

### 基本構文

基本の文は単にコマンドを実行するものである。先頭の単語がコマンド名として認識され実行される。"`echo`" などの内部コマンドの場合と外部コマンドの場合がある。それに続く単語列は、そのコマンドの引数として渡される。

基本構文レベルでは、以下のような文法の機能が存在する。

### 制御構造

csh は条件分岐と反復という制御構造を提供している。条件分岐としては `if` 文と `switch`文がある。反復としては、`while` 文、`foreach` 文、`repeat` 文がある。

#### if文

`if` 文には2つの形式がある。短い形式は1行で済むが、式が真の場合に実行できるコマンドはひとつだけである。

長い形式は `then`、`else`、`endif` というキーワードを使いコマンドの並んだブロックを形成でき、その中でさらに条件分岐を入れ子にすることもできる。

`else` と `if` が同じ行に出現する場合、csh はそれを入れ子というよりも連鎖として扱う。つまり `endif` はひとつでよい。

#### switch文

`switch` 文は文字列をパターンの一覧と比較する。パターンにはワイルドカード文字を含んでもよい。どれもマッチしない場合 `default` アクションを実行し、マッチすればその部分を実行する。

#### while文

`while` 文は式を評価する。その結果が真なら続くコマンド群を実行し、再び式の評価に戻る。

#### foreach文

`foreach` 文は値の一覧(通常はワイルドカードで生成されたファイル名一覧)をとり、それぞれの値について値をループ変数に設定し、続くコマンド群を実行する。

#### repeat文

repeat文は「整数値」で指定された回数だけ「コマンド」を繰り返し実行する。

### 変数

csh はシェル変数と環境変数を実装している。環境変数は setenv 文で生成でき、その値は常に単純な文字列であり、`exec` システムコール経由任意の子プロセスに引き継がれる。

シェル変数は `set` 文や `@` 文で生成され csh 内部で使われる。子プロセスには渡されない。シェル変数は単純な文字列の場合と文字列の配列の場合がある。事前定義されたシェル変数もいくつかあり、csh 内部の各種オプションの制御に使われる。例えば、ワイルドカードが何にもマッチしなかった際の動作などを設定できる。

現在のバージョンの csh では、変数に格納できる文字列の長さは任意であり、数百万文字でもよい。

### 式

C shell はC言語の演算子を流用した文法で32ビット整数の式を評価する機能を実装している。他に文字列比較の演算子やファイルシステムのテスト演算子(あるファイルが存在するかどうかのテスト)もある。演算子とオペランドは空白で区切らなければならない。変数は `$`name の形式で参照する。

演算子の優先順位もC言語を踏襲しているが、優先順位の等しい演算子が並んでいるときの演算順序の曖昧さを解決する演算子の結合性はC言語とは異なる。C言語では多くの演算子で左から右へ結合していくのに対し、C shell では右から左に結合していく。以下に例を示す。

|  |  |  |  |  |
| --- | --- | --- | --- | --- |
|  |  | ``` // C groups from the left // prints 4 int i = 10 / 5 * 2; printf( "%d\n", i ); // prints 5 i = 7 - 4 + 2; printf( "%d\n", i ); // prints 16 i = 2 >> 1 << 4; printf( "%d\n", i ); ``` |  | ``` # C shell groups from the right # prints 1 @ i = 10 / 5 * 2 echo $i # prints 1 @ i = 7 - 4 + 2 echo $i # prints 0 @ i = ( 2 >> 1 << 4 ) echo $i ``` |

C shell での括弧はビットシフト演算子と入出力リダイレクトを混同しないために使用している。どちらの言語でも括弧を使えば評価順序を明確化できる。なお先述した通り、シェル変数の値は文字列であり、@ 文などの式の中でだけ文字列を数値に変換して評価し、結果を文字列に変換して変数に格納している。

## 批判

いくつもの革新的機能により対話型利用では人気となったが、csh はスクリプト言語としては人気を獲得することはなかった。当初から1980年代末まで、cshはあらゆるUnixシステムに実装されていたわけではなく、shならばあらゆるUnixシステムに存在することが確実だった。したがって、様々なシステムで動作する可能性のあるスクリプトはshで書くのが賢明だった。1990年代中ごろにはcshも広く利用可能となったが、POSIXの委員会からcshをスクリプト言語として使用することに対して批判の声が挙がった。すなわち、対話用とスクリプト用の推奨シェルは1つであるべきだとし、POSIXとしては KornShell を推奨するとしたのである。C shell は他にも、文法上の欠陥、機能不足、実装のまずさといった点で批判された。

対話的にコマンドを入力して実行するぶんには快適だが、複雑なコマンドを実行させようとスクリプトを書いてみると時間がかかり、しかもよく失敗し、暗号のようなエラーメッセージを表示するか、好ましくない結果を生じることになる。例えば、C shell では制御構造間のパイプは不可能である。例えば `foreach` の出力をパイプで `grep` コマンドに送り込もうとしても単に機能しない。ワークアラウンドとしては、`foreach` を使った部分を別のスクリプトにして構文解析の問題を回避するという手段がある。こうすれば、そのスクリプトは別のcshのプロセスとして動作するのでパイプで接続することも自由である。

別の好ましくない動作の例としてコード断片を示す。下記のスクリプトはどちらも「'myfile' が存在しないなら、'mytext' をそこに書き込む形で生成せよ」という意味である。しかし、右側の例では常に空ファイルが生成される。何故なら C shell の評価順序はコマンド行単位であり、まず入出力リダイレクトを評価することになっているためで、myfile がその際に作られてしまい、ファイルの存在を調べたときには既に存在しているためである。

|  |  |  |  |  |
| --- | --- | --- | --- | --- |
|  |  | ``` # Works as expected if ( ! -e myfile ) then    echo mytext > myfile endif ``` |  | ``` # Always creates an empty file if ( ! -e myfile ) echo mytext > myfile ``` |

また、エラーメッセージが貧弱だという点もよく批判されている。例えば "0 event not found" というメッセージからは何が問題なのかもわからない。

## 影響

ヒストリ機構、エイリアス、チルダ記法、対話的ファイル名補完、シェル内での式評価などといった機能は大きな成功だったと言え、他のUnixシェルでも採用された。しかしkshやbashなど多数の独立したクローンが生まれたshとは対照的に、cshのクローンとして知られているものは2つしかない(tcshはcshと独立して開発されたわけではなく、クローンとは言えない。tcshはビル・ジョイの書いたオリジナルのコードをベースとして機能を追加しただけである)。

アレン・ホーラブの1986年の著書 On Command: Writing a Unix-Like Shell for MS-DOS では、"SH" という名前のプログラムを解説しているが、これはshではなくcshの機能と言語設計をコピーしたものである。関連するフロッピーディスクにはSHと基本的なUnix風コマンド(cat、cp、grep など)のソースコードが格納されていて、それぞれ25ドルと30ドルで販売されていた。ホーラブのSHの制御構造、式の文法、ヒストリ機構などは全て C shell と同一だった。

1988年、Hamilton Laboratories がOS/2向けに Hamilton C shell を発売した。1992年には Windows NT 版をリリース。Windows版はその後も活発にサポートされているが、OS/2版は2003年でサポート終了している。Hamilton C shell は Nicole Hamilton が書いたもので、cshクローンとUnixユーティリティ群を含んでいる。初期のクイックリファレンスによれば、「(ジョブコントロールを除く)C shell 言語全体に完全準拠」としているが、言語仕様には若干の改良が見られ、UnixとPCの差異にも対応している。最大の改良点はトップダウン構文解析を採用した点で、制御構造の入れ子やパイプ連結が可能となっている。また、プロシージャを定義でき、ブロック構造に局所変数を定義でき、浮動小数点演算もサポートしている。PC向けの改良点としては、ファイル名などのPCにおける慣習に従っており、スレッドの生成で済む部分は子プロセスを生成するのではなくスレッドで対応している。

音声認識研究の分野では C shell がスクリプト言語としてよく使われている。これはHTKというツールがcshスクリプトを使っていることと関連している。