削除された内容 追加された内容
ZéroBot (会話 | 投稿記録)
m r2.7.1) (ロボットによる 追加: no:C shell
Melan (会話 | 投稿記録)
en:C shell(2012年4月12日 18:55:17(UTC))の翻訳をマージ
タグ: サイズの大幅な増減
1行目:
{{Infobox Software
'''C shell'''(シーシェル、'''csh''')は、[[BSD]] UNIXシステム上で[[ビル・ジョイ]]によって開発された[[シェル]]である。[[UNIX]] V6 の /bin/sh を元に作られたもので、[[Bourne shell]] (UNIX V7)と共通の先祖を持つ。その文法は[[C言語]]をモデルとしている。とはいうものの、C言語のように関数が作れるわけではなく、代わりにエイリアスが使えるが貧弱であり、C Shell スクリプトでまともに構造化プログラミングを行うことはできない(Bourne shell やその互換シェルである Korn Shell、Bourne Again Shell、[[Z Shell]] 等では、C言語のように関数をつくり、構造化プログラミングを行うことができる)。Bourne shell に比較して、エイリアスやコマンド履歴などの便利な機能が豊富であった。今日では C shell はほとんど使われておらず、[[tcsh]]、[[Korn Shell]] (ksh)、[[Bourne Again Shell]] (bash)などに取って代わられた。
| 名称 = C shell
| 開発者 = [[ビル・ジョイ]]
| 初版 = 1978年
| 最新版 = tcsh 6.18.00
| 最新版発表日 = {{release date and age|2012|01|14}}<ref>{{Citation| last = Zoulas | first = Christos | title = tcsh-6.18 is now available | date = Jan 14 2012 | url = http://mx.gw.com/pipermail/tcsh/2012-January/004523.html | accessdate = 2012-01-16}}</ref>
| プログラミング言語 = [[C言語|C]]
| 対応OS = [[BSD]], [[UNIX]], [[Linux]], [[Mac OS X]]
| 種別 = [[シェル]]
| ライセンス = [[BSDライセンス]]
}}
 
'''C shell'''(シーシェル、'''csh''')は、[[カリフォルニア大学バークレー校]]の大学院生だった[[ビル・ジョイ]]が1970年代後半に開発した[[シェル|Unixシェル]]である。1978年にジョイが配布を始めた 2BSD という [[BSD]] UNIX のリリースで広く配布されることになった<ref>Harley Hahn, [http://unix.harley.com/instructors/timeline.html Harley Hahn's Guide to Unix and Linux].</ref><ref>[http://coe.berkeley.edu/labnotes/history_unix.html Berkeley Engineering Lab Notes, Volume 1, Issue 2, October 2001].</ref>。他にアイデアやコードに貢献した者としては、マイケル・ウベル、[[エリック・オールマン]]、マイク・オブライエン、ジム・カルプがいる<ref>[http://www.kitebird.com/csh-tcsh-book/csh-intro.pdf ''An Introduction to the C shell''] by [[ビル・ジョイ|Bill Joy]].</ref>。[[UNIX]] V6 の /bin/sh を元に作られたもので、[[Bourne shell]] (UNIX V7)と共通の先祖を持つ。
== 機能 ==
C shell は典型的なUNIXのシェル構造に従い、入力の各行(スクリプトの各行)をコマンドとして解釈して実行し、必要なら[[バックスラッシュ]]で改行を「エスケープ」して複数行をひとつのコマンドとして実行する。
 
通常テキストウィンドウ内で動作する[[コマンドラインインタプリタ]]であり、ユーザーがコマンドを入力するとそれに応じた処理が実行される。また[[シェルスクリプト]]と呼ばれるファイルからコマンド群を読み込むこともできる。他のUnixシェルと同様、ファイル名の[[ワイルドカード (情報処理)|ワイルドカード]]、[[パイプ (コンピュータ)|パイプ]]、[[ヒアドキュメント]]、{{仮リンク|コマンド置換|en|command substitution}}、[[変数 (プログラミング)|変数]]、条件分岐やループなどの[[制御構造]]をサポートしている。cshが1980年代の他のシェルと異なっていた点は、対話向けの機能と全体的なスタイルである。新機能によって他のシェルよりも容易に素早く使うことができた。言語としての全体的スタイルは[[C言語]]によく似ており、Unixユーザーにとっては読みやすかった。
以下の機能は C shell で初めて導入されたもので、今日ではUNIX系のシェルの多くがサポートしている。
 
;ジョブコントロール :対話型ジョブを一旦停止させ、後で再開させたり、バックグラウンドに移行させたりする。
[[Mac OS X]] や [[Red Hat Linux]] など多くのシステムのcshは実際には改良版の[[tcsh]]である。tcshの実行ファイルは "csh" と "tcsh" の両方に[[ハードリンク]]されていて、どちらの名前でも同じ改良版のtcshが呼び出される。
;ヒストリ置換 :<code>!</code>-置換により、以前に実行したコマンドを再実行したり、その内容を編集できる。
 
;配列 :複数の要素を格納できる変数であり、要素を数値でインデックス付けする。
[[Ubuntu]]ではcshとtcshの2種類のパッケージを用意しており、前者はオリジナルのBSD版csh<ref>http://packages.ubuntu.com/oneiric/shells/csh</ref>、後者は改良版のtcsh<ref>http://packages.ubuntu.com/oneiric/shells/tcsh</ref>となっている。
;<code>[[~]]</code> 拡張 :[[ホームディレクトリ]]参照。
 
;エイリアス :コマンドやコマンド列の別名を設定できる。
tcshには、ファイル名やコマンドの補完機能、[[TOPS-20#TENEX|Tenex]]システムに由来するコマンド行編集があり、名称の先頭の "t" は Tenex に因んでいる<ref name=Greer>{{Cite newsgroup| author = Ken Greer| title = C shell with command and filename recognition/completion| date = Oct 3 1983| newsgroup = net.sources| url = http://groups.google.com/group/net.sources/msg/7073bf41cc5da330?hl=en| accessdate = 2010-12-29}}</ref>。tcshは機能を追加しただけでオリジナルのcshを修正したわけではないので、[[後方互換]]を保っていた<ref>[http://www.tcsh.org/tcsh.html/DESCRIPTION.html tcsh(1) man page]</ref>。当初はジョイが作ったオリジナルのソースツリーからの脇枝だったが、今ではtcshが主な枝となっていて、開発が継続されている。tcshは非常に安定しているが、主に細かいバグ修正のため、およそ1年に1回の頻度で新たなリリースがなされている<ref>Fixes file in tcsh-6.17.00.</ref>。
;算術演算 :Bourne shell では外部プログラムを使わないとできなかった計算を組み込みで可能にした。
 
== 設計目標と機能 ==
C shell の主たる設計目標は、[[C言語]]に似せることと、対話型利用での改良であった。
 
=== C言語風のスタイル ===
Unixシステムはほとんど全体がCで書かれているため、C shell の第一の目標はスタイル上システム全体と一貫性のあるコマンド言語とすることだった。キーワード、括弧の利用、組み込みの式の文法、配列サポートなどは全てCの影響を強く受けている。
 
今ではC言語によく似た文法の[[スクリプト言語]]がいくつもあり、それらに比べればcshはそれほどC言語に似ているとは言えない。しかし80年代から90年代にかけて、特に[[AT&T]]で[[スティーブン・ボーン]]が開発した[[Bourne Shell|sh]]と比べたときの違いは著しいと見られていた。次の例は、C shell の[[演算子]]や構文のわかりやすさを示したものである。
 
{{Columns|width=27em
|col1width=10px
|col1=
|col2width=27em
|col2=
<source lang="bash">
#!/bin/sh
if [ $days -gt 365 ]
then
echo This is over a year.
fi
</source>
|col3width=27em
|col3=
<source lang="bash">
#!/bin/csh
if ( $days > 365 ) then
echo This is over a year.
endif
</source>
}}
 
shには[[式 (プログラミング)|式]]の文法が存在しない。角括弧で囲まれた条件式は、外部の{{仮リンク|test (Unix)|en|test (Unix)|label=test}}というプログラムで評価する必要がある。つまり、shのifコマンドは[[子プロセス]]を起動して引数を別のコマンドとして実行させる。その子プロセスが終了したときの{{仮リンク|リターンコード|en|return code}}がゼロならthen節を探し(then節はifとは別の文だが、セミコロンをはさんで一行で書かれることが多い)、入れ子になったブロックを実行する。リターンコードがゼロ以外ならelse節を実行する。testプログラムを "<code>test</code>" と "<code>[</code>" の両方に[[ハードリンク]]することで、角括弧表記の利点が生まれ、testの機能があたかもshの一部であるかのような錯覚を与える。shで制御ブロックの終端にキーワードを逆に綴ったものを置くのは、[[ALGOL|ALGOL 68]] のスタイルを踏襲したものである<ref>[http://groups.google.com/group/comp.lang.misc/msg/d58db4799c33e093?hl=en&dmode=source ''Re: Late Bloomers Revisited''] USENET post to comp.lang.misc by Piercarlo "Peter" Grandi, Dept of CS, UCW Aberystwyth, UK, Dec 17, 1989.</ref>。
 
対照的にcshは自前で式を評価でき、高速である。[[可読性]]もよいと言われている。演算子や構文の多くはC言語のものをそのまま使っている。キーワードを逆に綴ることもなく、全体としてよりC言語に近いスタイルである。
 
次の例は、2の1乗から10乗までを計算するスクリプトを比較したものである。
 
{{Columns|width=27em
|col1width=10px
|col1=
|col2width=27em
|col2=
<source lang="bash">
#!/bin/sh
i=2
j=1
while [ $j -le 10 ]; do
echo '2 **' $j = $i
i=`expr $i '*' 2`
j=`expr $j + 1`
done
</source>
|col3width=27em
|col3=
<source lang="bash">
#!/bin/csh
set i = 2
set j = 1
while ( $j <= 10 )
echo '2 **' $j = $i
@ i *= 2
@ j++
end
</source>
}}
 
やはりshには式の文法が存在しないため、shのスクリプトは{{仮リンク|コマンド置換|en|command substitution}}と{{仮リンク|expr|en|expr}}コマンドを使っている。C shell の @ 文(コマンド)は一種の[[駄洒落]]であり、"at-sign-ment" すなわち代入文を意味している。
 
最後の例は、[[switch文]]のスタイルの違いを示したものである。
 
{{Columns|width=27em
|col1width=10px
|col1=
|col2width=27em
|col2=
<source lang="bash">
#!/bin/sh
for i in d*
do
case $i in
d?) echo $i is short ;;
*) echo $i is long ;;
esac
done
</source>
|col3width=27em
|col3=
<source lang="bash">
#!/bin/csh
foreach i ( d* )
switch ( $i )
case d?:
echo $i is short
breaksw
default:
echo $i is long
endsw
end
</source>
}}
 
shのスクリプトでは、"<code>;;</code>" で各ケースの終りを示す。通常は空文を許さないため、これはケースの終りを目立たせるためである。
 
=== 対話型利用のための改良点 ===
C shell の第二の設計目標は、対話型利用の改良だった。そのため、[[ユーザビリティ]]や入力の高速性を追求したいくつかの新機能を導入している。必要な結果を得るのに打ち込まなければならないキーストローク数を減らすことで、高速性を実現している。特に重要なのは、ヒストリとその編集機構、エイリアス、ディレクトリスタック、チルダ記法、cdpath、ジョブコントロール、パスハッシングである。これら新機能は人気となり、多くが他のUnixシェルにも採用された。
 
; ヒストリ
: 素早いキーストロークで以前に入力したコマンド行を呼び出して再実行することができる。例えば、[[感嘆符]]を2つ "<code>!!</code>" と入力すると、直前に入力したコマンドを再実行できる。他にも "<code>!$</code>" と入力すると直前のコマンド行の最後の引数に置換される。
; 編集機構
: 編集はヒストリ内のコマンドのテキストだけでなく、様々な置換が可能である。編集用作用素としては、単純な文字列検索/置換からファイルのパス名を構文解析して特定の部分を取り出すなどがある。
; エイリアス
: ユーザーが定義した何らかの文字列の別名(エイリアス)を設定でき、その別名を打ち込むと C shell がそれをユーザー定義文字列に置換する。例えば "<code>[[Grep|fgrep]]</code>" コマンドのエイリアスとして "<code>f</code>" を設定しておくとキーストロークが少なくなって高速化でき、スクリプトを作るよりも簡単である。
; ディレクトリスタック
: ディレクトリ[[スタック]]は、[[カレントディレクトリ]]をスタックにプッシュまたはポップでき、ファイルシステム内の複数個所で少ないキーストロークで行き来することができる。
; チルダ記法
: [[ホームディレクトリ]]を "<code>[[~]]</code>" で記述でき、ホームからの相対パスでファイルを指定できる。
; 対話的ファイル名補完
: [[Escキー]]を対話的に使用し、入力中のコマンド行の最後尾のファイル名を補完する可能性のある候補を示すことができる。
; cdpath
: コマンド検索パス([[環境変数]]のPATH)の記法で、[[cd (UNIX)|cd]]コマンドを拡張するシェル変数。cdコマンドで指定されたディレクトリが[[カレントディレクトリ]]にない場合、cdpathに指定されているディレクトリ群も調べる。
; ジョブコントロール
: 1980年代、多くのユーザーは単純なキャラクタ[[端末]]を使っていた。shの場合、一度に1つのことしかできなかった。ウィンドウを別に開くということができなかったため、ファイルの編集を開始するには、それまで行っていたことを終了させるなどする必要があった。C shell のジョブコントロールはこの問題を解決するもので、Ctrl-Z を押下することで現在実行中のジョブをサスペンドし、新たな C shell のインスタンスを生成することができる。そして、<code>fg</code> コマンドで複数のジョブを切り換えることができる。アクティブなジョブはフォアグラウンドジョブと呼ぶ。それ以外のジョブはサスペンド状態かまたはバックグラウンド状態となる。
; パスハッシング
: パスハッシングとは、実行可能ファイルの検索を高速化する機能である。PATHに示されたディレクトリを順に見ていくのではなく、C shell 内部に構築したハッシュテーブルから実行可能ファイルを探す。"rehash" コマンドはそのハッシュテーブルをリフレッシュするもので、新たに実行可能ファイルを作成した場合などに使用する。
 
== スクリプト言語としての C Shell ==
C shell は行単位で操作する。各行を[[字句解析]]して空白、括弧、パイプやリダイレクトを表す記号、セミコロン、アンパサンド等で区切られた単語の並びとして認識する。
C shell は対話モードでは様々な発明的機能を導入したが、[[スクリプト言語]]としての機能には批判が多い。いずれにしても、[[UNIX]]系システムには必ず Bourne shell が存在するので、スクリプトを書く場合には csh ではなく sh を使うことが推奨される(ksh や bash も Bourne shell とほぼ同じ文法である)。
 
=== 基本構文 ===
cshスクリプトの歓迎できない挙動の例として、以下のようなものがある:
基本の文は単にコマンドを実行するものである。先頭の単語がコマンド名として認識され実行される。"<code>echo</code>" などの内部コマンドの場合と外部コマンドの場合がある。それに続く単語列は、そのコマンドの引数として渡される。
if ( ! -e foo ) echo bar > foo
これは、「ファイル''foo''が存在していないなら、''bar''の内容によってそれを作成せよ」ということを意味している。しかしこの行が構文解析されたとき、ファイルの存在がチェックされる前に出力のリダイレクトが設定されるため、実のところ空のファイルが作成されるだろう。
 
基本構文レベルでは、以下のような文法の機能が存在する。
しかし csh の文法では算術演算が可能であり、sh では外部プログラムを呼ばないとそれができない。
 
; [[ワイルドカード (情報処理)|ワイルドカード]]
スクリプトを csh で書くなら、<tt>-f</tt> フラグを付けて使う方がよいだろう(つまり、スクリプトの先頭に <tt>#!/bin/csh&nbsp;-f<tt> という行を入れる)。こうすると、スクリプトの実行時にユーザーのセットアップファイルを実行しないので、ユーザーによってスクリプトの動作が変わってくるようなことが起きない。
: 他のUnixシェルと同様、任意のコマンド行引数にワイルドカードを使用できる。ワイルドカード文字を含む単語がある場合、それをパターンとし、マッチするファイル名の一覧と置換する。
:: <code>*</code> は、任意長の文字列とマッチする。
:: <code>?</code> は、任意の1つの文字とマッチする。
:: <code>[</code>...<code>]</code> は、角括弧内の任意の文字とマッチする。ハイフンで範囲指定することもできる。
:: <code>[!</code>...<code>]</code> は、角括弧内の文字以外の任意の文字とマッチする。
: cshではいくつか便利な記法を導入しており、他のUnixシェルにも採用されている。
:: ''abc''<code>{</code>''def''<code>,</code>''ghi''<code>}</code> は、''abcdef'' または ''abcghi'' に展開される。
:: <code>~</code> は、カレントユーザーのホームディレクトリを意味する。
:: <code>~</code>''user'' は、その ''user'' のホームディレクトリを意味する。
: 複数ディレクトリレベルのワイルドカード、例えば "<code>*/*.c</code>" といった記述も可能である。
: ワイルドカード処理をシェルが行うようにしたことは、Unixにおける重要な決定の1つである。つまり、どのコマンドでも同じようにワイルドカードが使え、シェルだけがワイルドカード処理に必要なコードを備えていればよい。しかし、そのために[[子プロセス]]生成時の{{仮リンク|exec (OS)|en|exec (operating system)|label=exec}}システムコールには非常に長い引数を効率的に渡す必要が生じた。対照的に[[Microsoft Windows|Windows]]はコマンド行を[[Unicode]]でおよそ32K文字までに制限しており、ワイルドカード処理は各アプリケーションが行うようになっている(実際にはC言語の<code>main()</code>関数を実行する前にCのランタイムコードが自動的に行う)。これは[[MS-DOS]]からの伝統である。MS-DOSではアプリケーションに渡せるコマンド行は128バイトに制限されていたため、ワイルドカード処理をコマンドプロンプト側で行うのは非現実的だった。
; 入出力[[リダイレクト (CLI)|リダイレクト]]
: cshでコマンドを実行する場合、デフォルトではcshの[[標準ストリーム|標準入力]]/[[標準ストリーム|標準出力]]/[[標準ストリーム|標準エラー出力]]をそのまま継承し、それらはcshが動作している端末(または[[端末エミュレータ]])を指しているのが普通である。入出力リダイレクトを行うことで入力または出力に端末ではなくファイルを使うよう設定できる。
::<code>> </code>''file'' は、標準出力が ''file'' に書かれることを意味する。既存ファイルの場合は上書きし、無ければ新規作成する。エラーはシェルのウィンドウに表示される。
::<code>>& </code>''file'' は、標準出力と標準エラー出力の両方が ''file'' に書かれることを意味する。既存ファイルの場合は上書きし、無ければ新規作成する。
::<code>>> </code>''file'' は、標準出力が ''file'' の最後尾に追記されることを意味する。
::<code>>>& </code>''file'' は、標準出力と標準エラー出力の両方が ''file'' の最後尾に追記されることを意味する。
::<code>< </code>''file'' は、''file'' から標準入力に読み込むことを意味する。
::<code><< </code>''string'' は、[[ヒアドキュメント]]である。''string'' にマッチする行が入力されるまでの入力内容を標準入力として読み込む。
; 連結
: コマンドは、次のような手段で1行に複数個連結することができる。
::<code>;</code> は、1つめのコマンドを実行し、次に2つめのコマンドを実行することを意味する。
::<code>&&</code> は、1つめのコマンドを実行し、その{{仮リンク|リターンコード|en|return code}}が0(成功)の場合、2つめのコマンドを実行する。
::<code>||</code> は、1つめのコマンドを実行し、リターンコードが0以外(失敗)の場合に2つめのコマンドを実行する。
; [[パイプ (コンピュータ)|パイプ]]
: 複数のコマンドをパイプで接続でき、あるコマンドの出力を次のコマンドの入力とすることができる。この場合、2つのコマンドは並行して動作する。
::<code>|</code> は、前のコマンドの標準出力を次のコマンドの標準入力に接続する。エラーはシェルのウィンドウに表示される。
::<code>|&</code> は、前のコマンドの標準出力と標準エラー出力を次のコマンドの標準入力に接続する。
; 変数置換
: 単語にドル記号 "<code>$</code>" がある場合、それに続く文字列を変数名と解釈し、その変数の値で置換する。変数にパス名を入れておくと、ヒストリの編集機構を使って特定部分(ファイル拡張子やファイル名本体のみなど)を取り出すこともできる。
; 引用符とエスケープ
: 引用機構は、空白、ワイルドカード、括弧、ドル記号など通常なら特殊な意味を持つ文字を[[リテラル]]テキストとして扱えるようにする。
:: <code>\</code> は、続く文字を通常のリテラル文字として扱う。
:: <code>"</code>''string''<code>"</code> は弱い引用である。空白やワイルドカードはリテラルとして扱われるが、変数やコマンド置換はそのまま機能する。
:: <code>'</code>''string''<code>'</code> は強い引用である。囲まれた文字列全体がリテラルとして扱われる。
; コマンド置換
: コマンド置換は、あるコマンドの出力を別のコマンドの引数として使えるようにする。
:: <code>`</code>''command''<code>`</code> は ''command'' を実行し、その出力でコマンド行の当該部分を置換する。
; バックグラウンド実行
: 通常、コマンドを実行開始するとそれが終わるのを待ち合わせ、次のコマンドを実行するか、ユーザーのコマンド入力を促すプロンプトを表示する。
:: ''command''<code> &</code> は、''command'' をバックグラウンドで実行開始し、即座に次のコマンドを受け付けられるようにする。
; サブシェル
: サブシェルはシェルの子プロセスであり、現在の状態を継承しているが、それを変更することもできる。例えば、カレントディレクトリを変更しても親のカレントディレクトリは変化しない。
::<code>( </code>''commands''<code> )</code> は、''commands'' をサブシェルで実行することを意味する。
 
=== 制御構造 ===
csh は[[If文|条件分岐]]と[[イテレータ|反復]]という[[制御構造]]を提供している。条件分岐としてはif文とswitch文がある。反復としては、while文、foreach文、repeat文がある。
 
; if文
: if文には2つの形式がある。短い形式は1行で済むが、式が真の場合に実行できるコマンドは1つだけとなる。
::'''if ( '''''expression''''' ) '''''command''
: 長い形式は then、else、endif というキーワードを使いコマンドの並んだブロックを形成でき、その中でさらに条件分岐を入れ子にすることもできる。
::'''if ( '''''expression1''''' ) then'''
:::''commands''
::'''else if ( '''''expression2''''' ) then'''
:::''commands''
::...
::'''else'''
:::''commands''
::'''endif'''
: else と if が同じ行に出現する場合、csh はそれを入れ子というよりも連鎖として扱う。つまり、endif は1つでよい。
; switch文
: switch文は文字列をパターンの一覧と比較する。パターンにはワイルドカード文字を含んでもよい。どれもマッチしない場合 default アクションを実行し、マッチすればその部分を実行する。
::'''switch ( '''''string''''' )'''
:::'''case '''''pattern1''''':'''
::::''commands''
::::'''breaksw'''
:::'''case '''''pattern2''''':'''
::::''commands''
::::'''breaksw'''
:::...
:::'''default:'''
::::''commands''
::::'''breaksw'''
::'''endsw'''
; while文
: while文は式を評価する。その結果が真なら続くコマンド群を実行し、再び式の評価に戻る。
::'''while ( '''''expression''''' )'''
:::''commands''
::'''end'''
; foreach文
: foreach文は値の一覧(通常はワイルドカードで生成されたファイル名一覧)をとり、それぞれの値について値をループ変数に設定し、続くコマンド群を実行する。
::'''foreach '''''loop-variable''''' ( '''''list-of-values''''' )'''
:::''commands''
::'''end'''
; repeat文
: repeat文は、integer で指定された回数だけ command (1つのコマンド)を繰り返し実行する。
::'''repeat''' ''integer'' ''command''
 
=== 変数 ===
C shell はシェル変数と[[環境変数]]を実装している。環境変数は setenv 文で生成でき、その値は常に単純な文字列であり、任意の[[子プロセス]]に引き継がれ、execシステムコール経由で main 関数の envp[] 引数で渡される。
 
シェル変数は set 文や @ 文で生成されcsh内部で使われる。子プロセスには渡されない。シェル変数は単純な文字列の場合と文字列の配列の場合がある。事前定義されたシェル変数もいくつかあり、csh内部の各種オプションの制御に使われる。例えば、ワイルドカードが何にもマッチしなかった際の動作などを設定できる。
 
現在のバージョンのcshでは、変数に格納できる文字列の長さは任意であり、数百万文字でもよい。
 
=== 式 ===
C shell はC言語の演算子を流用した文法で32ビット整数の式を評価する機能を実装している。他に文字列比較の演算子やファイルシステムのテスト演算子(あるファイルが存在するかどうかのテスト)もある。演算子とオペランドは空白で区切らなければならない。変数は <code>$</code>''name'' の形式で参照する。
 
演算子の優先順位もC言語を踏襲しているが、演算子の結合性はC言語とは異なり、優先順位の等しい演算子が並んでいるときの曖昧さを解消しようとしている。C言語では多くの演算子で左から右へ結合していくのに対し、C shell では右から左に結合していく。以下に例を示す。
 
{{Columns|width=27em
|col1width=10px
|col1=
|col2width=27em
|col2=
<source lang="c">
// 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 );
</source>
|col3width=27em
|col3=
<source lang="bash">
# 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
</source>
}}
 
C shell での括弧はビットシフト演算子と入出力リダイレクトを混同しないために使用している。どちらの言語でも括弧を使えば評価順序を明確化できる。なお先述した通り、シェル変数の値は文字列であり、@ 文などの式の中でだけ文字列を数値に変換して評価し、結果を文字列に変換して変数に格納している。
 
== 批判 ==
いくつもの革新的機能により対話型利用では人気となったが、csh はスクリプト言語としては人気を獲得することはなかった。当初から1980年代末まで、cshはあらゆるUnixシステムに実装されていたわけではなく、shならばあらゆるUnixシステムに存在することが確実だった。したがって、様々なシステムで動作する可能性のあるスクリプトはshで書くのが賢明だった。1990年代中ごろにはcshも広く利用可能となったが、[[POSIX]]の委員会からcshをスクリプト言語として使用することに対して批判の声が挙がった<ref>''IEEE Standard for Information Technology, Portable Operating System Interface (POSIX), Part 2: Shell and Utilities, Volume 2''. IEEE Std 1003.2-1992, pp. 766-767. ISBN 1-55937-255-9.</ref>。すなわち、対話用とスクリプト用の推奨シェルは1つであるべきだとし、POSIXとしては [[Korn Shell]] を推奨するとしたのである。C shell は他にも、文法上の欠陥、機能不足、実装のまずさといった点で批判された<ref>[http://www.faqs.org/faqs/unix-faq/shell/csh-whynot/ ''Csh Programming Considered Harmful''] by Tom Christiansen</ref><ref>[http://www.grymoire.com/Unix/CshTop10.txt ''Top Ten Reasons not to use the C shell''] by Bruce Barnett</ref>。
 
; 文法上の欠陥
: 言語定義上、不必要な矛盾が生じている。例えば、<code>set</code>、<code>setenv</code>、<code>alias</code> というコマンドは、ある名前と文字列または単語の並びを結びつけるという基本的に同じ機能を有している。しかし、それらには全く不必要な若干の差異がある。<code>set</code> では等号を必要とするが、<code>setenv</code> や <code>alias</code> では等号は使わない。<code>set</code> では単語の並びを括弧で囲む必要があるが、<code>setenv</code> と <code>alias</code> ではそうではない。同様に、<code>if</code> の最後は <code>endif</code>、<code>switch</code> の最後は <code>endsw</code>、ループ系構文では最後が <code>end</code> というように意味も無く一貫性がない文法になっている。
; 機能不足
: よく言われるのは、[[Fgetc|標準入力]]ファイルハンドルの操作機能と関数サポートの欠如である。Bourne shell は局所変数は使えないが関数は定義できるのに対し、csh で関数に相当する機能はエイリアスしかなく、1行のコードしか定義できず、しかも制御構文の多くは途中に改行を必要とする。結果としてスタイルは似ていてもC言語のプログラムの機能をそのまま C shell で実装するのは困難である。そのため、大きなプロジェクトほどC言語や Bourne shell のスクリプトを使う傾向がある。
; 実装のまずさ
: [[構文解析]]は場当たり的であり、多くの批判を浴びている。1970年代初めには[[コンパイラ]]技術はそれなりに成熟しており<ref>David Gries (1971). ''Compiler Construction for Digital Computers.'' John Wiley & Sons. ISBN 0-471-32776-X.</ref>、多くの言語は[[トップダウン構文解析|トップダウン]]または[[ボトムアップ構文解析|ボトムアップ構文解析器]]を使って完全に再帰的な[[形式文法|文法]]を認識できるように実装されていた。C shell で場当たり的な設計となった理由は不明である。ジョイは2009年のインタビューで「Unixに関して作業を始めたとき、私は優秀なプログラマではなかった」と述べており、単にそれが答えかもしれない<ref>[http://fora.tv/2009/02/11/Bill_Joy_in_Conversation_with_Brent_Schlender Bill Joy in Conversation with Brent Schlender, Churchill Club, Santa Clara, CA, Feb 11, 2009].</ref>。しかし、場当たり的な設計を選択したせいで C shell は完全再帰的ではなくなった。したがって、実現できる処理の複雑さには限度がある。
 
対話的にコマンドを入力して実行するぶんには快適だが、複雑なコマンドを実行させようとスクリプトを書いてみると時間がかかり、しかもよく失敗し、暗号のようなエラーメッセージを表示するか、好ましくない結果を生じることになる。例えば、C shell では制御構造間のパイプは不可能である。例えば <code>foreach</code> の出力をパイプで <code>[[grep]]</code> コマンドに送り込もうとしても単に機能しない。ワークアラウンドとしては、<code>foreach</code> を使った部分を別のスクリプトにして構文解析の問題を回避するという手段がある。こうすれば、そのスクリプトは別のcshのプロセスとして動作するのでパイプで接続することも自由である。
 
別の好ましくない動作の例としてコード断片を示す。下記のスクリプトはどちらも「'myfile' が存在しないなら、'mytext' をそこに書き込む形で生成せよ」という意味である。しかし、右側の例では常に空ファイルが生成される。何故なら C shell の評価順序はコマンド行単位であり、まず入出力リダイレクトを評価することになっているためで、myfile がその際に作られてしまい、ファイルの存在を調べたときには既に存在しているためである。
 
{{Columns|width=27em
|col1width=10px
|col1=
|col2width=27em
|col2=
<source lang="bash">
# Works as expected
if ( ! -e myfile ) then
echo mytext > myfile
endif
</source>
|col3width=27em
|col3=
<source lang="bash">
# Always creates an empty file
if ( ! -e myfile ) echo mytext > myfile
</source>
}}
 
また、エラーメッセージが貧弱だという点もよく批判されている。例えば "0 event not found" というメッセージからは何が問題なのかもわからない。
 
== 影響 ==
ヒストリ機構、エイリアス、チルダ記法、対話的ファイル名補完、シェル内での式評価などといった機能は大きな成功だったと言え、他のUnixシェルでも採用された。しかし[[Korn Shell|ksh]]や[[bash]]など多数の独立したクローンが生まれた[[Bourne Shell|sh]]とは対照的に、cshのクローンとして知られているものは2つしかない(tcshはcshと独立して開発されたわけではなく、クローンとは言えない。tcshはビル・ジョイの書いたオリジナルのコードをベースとして機能を追加しただけである)。
 
{{仮リンク|アレン・ホーラブ|en|Allen Holub}}の1986年の著書 ''On Command: Writing a Unix-Like Shell for [[MS-DOS]]''<ref>{{Cite book| first = Allen | last = Holub | year = 1986, 1987 | edition = Second | title = On Command: Writing a Unix-Like Shell for MS-DOS | publisher = M&T Books, Redwood City, CA | isbn = 0-934375-29-1}}</ref> では、"SH" という名前のプログラムを解説しているが、これはshではなくcshの機能と言語設計をコピーしたものである。関連するフロッピーディスクにはSHと基本的なUnix風コマンド(cat、cp、grep など)のソースコードが格納されていて、それぞれ25ドルと30ドルで販売されていた。ホーラブのSHの制御構造、式の文法、ヒストリ機構などは全て C shell と同一だった。
 
1988年、Hamilton Laboratories が[[OS/2]]向けに [[:en:Hamilton C shell|Hamilton C shell]] を発売した<ref>{{Cite journal| last = Hamilton | first = Douglas | title = Hamilton C shell Announcement | journal = IBM Personal Systems Developer | issue = Summer 1989 | pages = 119–121 | url = http://hamiltonlabs.com/archives/Hamilton-C-Shell-Announcement-Douglas-A-Hamilton-IBM-Personal-Systems-Developer-Summer-1989.pdf | accessdate =2010-11-22}}</ref>。1992年には [[Microsoft Windows NT|Windows NT]] 版をリリース<ref>[http://hamiltonlabs.com/ReleaseNotes.htm Hamilton C shell for Windows Release Notes 4.0], retrieved June 19, 2010.</ref>。Windows版はその後も活発にサポートされているが<ref>{{Cite web| last = Oliver | first = Robert | title = Hamilton C Shell 2009 – The Missing Shell for Windows | date = 19 September 2009 | url = http://www.4gigs.com/2009/09/19/hamilton-c-shell-2009-the-missing-shell-for-windows/ | accessdate =2010-06-24}}{{リンク切れ|date=2012年5月}}</ref>、OS/2版は2003年でサポート終了している。Hamilton C shell は Nicole Hamilton が書いたもので、cshクローンとUnixユーティリティ群を含んでいる。初期のクイックリファレンスによれば<ref>{{Cite book| title = Hamilton C shell Quick Reference | publisher = Hamilton Laboratories, Wayland, MA | date = 1988 - 1990 (Revised July 10, 1990) | url = http://hamiltonlabs.com/archives/1990-07-10-Hamilton-C-shell-Quick-Reference.pdf | accessdate =2010-11-22}}</ref>、「(ジョブコントロールを除く)C shell 言語全体に完全準拠」としているが、言語仕様には若干の改良が見られ、UnixとPCの差異にも対応している。最大の改良点は[[トップダウン構文解析]]を採用した点で、[[制御構造]]の入れ子やパイプ連結が可能となっている。また、プロシージャを定義でき、ブロック構造に局所変数を定義でき、浮動小数点演算もサポートしている。PC向けの改良点としては、ファイル名などのPCにおける慣習に従っており、[[スレッド (コンピュータ)|スレッド]]の生成で済む部分は子プロセスを生成するのではなくスレッドで対応している。
 
[[音声認識]]研究の分野では C shell がスクリプト言語としてよく使われている。これはHTKというツール<ref>[http://htk.eng.cam.ac.uk/ htk]</ref>がcshスクリプトを使っていることと関連している。
 
== 脚注 ==
{{Reflist}}
 
== 参考文献 ==
27 ⟶ 341行目:
*{{Cite book|和書|author=Paul DuBois|others=[[鈴鹿倫之]]・[[福澤康裕]]訳|year=2002|month=2|title=入門 csh & tcsh|publisher=オライリー・ジャパン|isbn=4-87311-073-4|url=http://www.oreilly.co.jp/books/4873110734/}}
*{{Cite book|和書|author=Arnold Robbins|coauthors=Nelson H. F. Beebe|others=[[日向あおい]]訳|year=2006|month=1|title=詳解シェルスクリプト|publisher=オライリー・ジャパン|isbn=4-87311-267-2|url=http://www.oreilly.co.jp/books/4873112672/}}
* {{Cite book| first = Paul | last = Wang | year = 1988 | title = An Introduction to Berkeley UNIX | publisher = Wadsworth Pub. Co. | isbn = 0-534-08862-7}}
* {{Cite book| first = Martin R. | last = Arick | year = 1993 | title = UNIX C Shell Desk Reference | publisher = John Wiley & Sons | isbn = 0-471-55680-7}}
* {{Cite web | title = Introduction to C Shell Programming | publisher = Canisius College Computer Science Department | url = http://klaatu.canisius.edu/ONLINESTUFF/UNIX/shellprogramming.html | accessdate = 2010-06-23}}
 
== 関連項目 ==
* [[コマンドラインインタプリタ]]
 
== 外部リンク ==
* [http://www.kiso.tsukuba.ac.jp/~makimura/text/node239.html 有害な csh プログラミング]
* [http://www.math.h.kyoto-u.ac.jp/~takasaki/edu/c/cshell.txt Cシェルプログラミング]
* [http://www.kitebird.com/csh-tcsh-book/csh-intro.pdf ''An Introduction to the C shell''] by [[ビル・ジョイ|William Joy]].
{{Computer-stub}}
* [http://docstore.mik.ua/orelly/linux/lnut/ch08_01.htm Linux in a Nutshell: Chapter 8. csh and tcsh].
* [http://www.tcsh.org/Home tcsh home page.]
* [http://www.tcsh.org/tcsh.html/top.html tcsh(1) man page.]
* [http://www.tcsh.org/MostRecentRelease most recent tcsh source code.]
* [http://minnie.tuhs.org/cgi-bin/utree.pl?file=2BSD/src/csh historical 2BSD csh source code] dated February 2, 1980.
* [http://minnie.tuhs.org/cgi-bin/utree.pl The Unix Tree], complete historical Unix distributions.
 
[[Category:Unixシェル]]