
Cシェル(cshまたは改良版のtcsh)は、1970年代後半にカリフォルニア大学バークレー校の大学院生だったビル・ジョイによって作成されたUnixシェルです。ジョイが1978年に初めて配布したBerkeley Software Distribution(BSD)の2BSDリリースを皮切りに、広く普及しました。 [ 1 ] [ 2 ]アイデアやコードに初期から貢献した人物には、マイケル・ウベル、エリック・オールマン、マイク・オブライエン、ジム・カルプなどがいます。[ 3 ]
Cシェルは、通常テキストウィンドウで実行されるコマンドプロセッサであり、ユーザーがコマンドを入力して実行できるようにします。Cシェルは、スクリプトと呼ばれるファイルからコマンドを読み込むこともできます。すべてのUnixシェルと同様に、ファイル名のワイルドカード、パイプ、ヒアドキュメント、コマンド置換、変数、条件テストと反復のための制御構造をサポートしています。特に1980年代において、Cシェルを他のシェルと区別していたのは、その対話型機能と全体的なスタイルでした。新しい機能により、より簡単かつ迅速に使用できるようになりました。言語の全体的なスタイルはC言語に似ており、より読みやすいと見なされていました。
macOSやRed Hat Linuxなど多くのシステムでは、csh は実際にはcsh の改良版であるtcshです。多くの場合、2 つのファイルのうち一方が他方へのハードリンクまたはシンボリックリンクになっているため、どちらの名前でも同じ改良版の C シェルが参照されます。オリジナルの csh ソース コード ( )src/bin/csh/とバイナリはNetBSDおよびOpenBSDに含まれています。
Debianおよび一部の派生ディストリビューション ( Ubuntuを含む)には、csh と tcsh という 2 つの異なるパッケージがあります。前者はオリジナルの BSD 版 csh [ 4 ] [ 5 ]に基づいており、後者は改良版の tcsh です。[ 6 ] [ 7 ]
tcsh は、ファイル名とコマンドの補完、コマンドライン編集の概念をTenexシステムから借用しており、これが「t」の由来です。[ 8 ]既存のものを変更せず機能を追加しただけなので、tcsh は元の C シェルとの後方互換性を維持しています。 [ 9 ] Joy が作成した元のソース ツリーからのサイド ブランチとして始まったものの、tcsh は現在、継続的な開発のメイン ブランチとなっています。tcsh は非常に安定していますが、主にマイナー バグの修正からなる新しいリリースが、ほぼ 1 年に 1 回リリースされ続けています。[ 10 ]
Cシェルの主な設計目標は、C言語により近い外観にすることと、対話的な使用に適していることであった。
UnixシステムはほぼすべてC言語で書かれていたため、Cシェルの最初の目標は、システム全体とよりスタイル的に一貫性のあるコマンド言語を提供することでした。キーワード、括弧の使用、Cシェルの組み込み式文法、配列のサポートなどはすべてC言語の影響を強く受けています。
現代の基準からすると、Cシェルは他の多くの一般的なスクリプト言語と比べて、特にC言語に似ているとは言えないかもしれません。しかし、1980年代から90年代にかけては、特にベル研究所のスティーブン・ボーンが開発した当時主流だったボーンシェル( shとも呼ばれる)と比較した場合、その違いは際立っていました。この例は、Cシェルのより一般的な式演算子と構文を示しています。
#!/bin/sh if [ $days -gt 365 ] then echoこれは1年以上経過しています。 fiCシェル
#!/bin/csh if ( $days > 365 ) then echoこれは1年以上経過しています。 endifBourne sh には式文法がありませんでした。角括弧で囲まれた条件は、外部テストプログラムを実行するという遅い方法で評価する必要がありました。sh のifコマンドは、引数の単語を子プロセスとして実行される新しいコマンドとして受け取ります。子プロセスがゼロリターン コードthenで終了した場合、shは節 (別のステートメントですが、多くの場合セミコロンで同じ行に結合されて記述されます) を探し、そのネストされたブロックを実行します。そうでない場合は、else を実行します。テスト プログラムを " " と " " の両方としてハード リンクすることで、角括弧の表記上の利点と、テストの機能が sh 言語の一部であるかのような外観が得られました。sh が制御ブロックの終了を示すために逆キーワードを使用するスタイルは、ALGOL 68から借用したものです。[ 11 ]test[
対照的に、cshは式を直接評価できるため、処理速度が速かった。また、可読性も優れているとされていた。その式は、主にC言語からコピーされた文法と演算子セットを使用しており、キーワードの順序が逆転しているものはなく、全体的なスタイルもC言語に似ていた。
2つ目の例として、2の最初の10乗を計算するスクリプトを比較してみましょう。
#!/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++ 終わり式文法がないため、sh スクリプトはコマンド置換とexprコマンドを使用します。(最新のPOSIX シェルにはそのような文法があり、ステートメントはi=$((i * 2))または と記述できます: "$((i *= 2))"。)
最後に、 switch文のさまざまなスタイルを示す3つ目の例を示します。
#!/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は短いです breaksw default : echo $iは長いです endsw endスクリプトではsh、「;;」は各ケースの終わりを示します。これは、sh がそれ以外の場合は null ステートメントを許可しないためです。
2つ目の目的は、Cシェルを対話型での使用に適したものにすることでした。ターミナルでコマンドを入力することで、より簡単、高速、かつ使いやすくする数多くの新機能が導入されました。ユーザーはより少ないキーストロークで作業を完了でき、処理速度も向上しました。これらの新機能の中で最も重要なものは、履歴と編集機能、エイリアス、ディレクトリスタック、チルダ表記、cdpath、ジョブ制御、パスハッシュなどです。これらの新機能は非常に人気が高く、その後、他のUnixシェルにも数多く採用されました。
履歴機能を使用すると、ユーザーは以前のコマンドを呼び出して、数回の簡単なキー操作だけで再実行できます。たとえば、コマンドとして感嘆符を2つ(" !!")[ 12 ]!$と入力すると、直前のコマンドが実行されます。その他の短いキー操作の組み合わせ(例:「 " 」(「前のコマンドの最後の引数」を意味します))を使用すると、以前のコマンドの断片を貼り付けて編集し、新しいコマンドを作成できます。
編集は、前のコマンドのテキストだけでなく、変数置換に対しても行うことができます。演算子は、単純な文字列検索/置換から、パス名を解析して特定のセグメントを抽出するものまで多岐にわたります。
エイリアスを使用すると、ユーザーはエイリアス名を入力するだけで、Cシェルがそれを内部的に展開して、ユーザーが定義した単語のセットに変換します。多くの単純な状況では、エイリアスはスクリプトよりも高速で便利です。
ディレクトリスタックを使用すると、ユーザーは現在の作業ディレクトリをプッシュまたはポップできるため、ファイルシステム内のさまざまな場所間を簡単に移動できます。
チルダ表記は、" "文字を使用してホームディレクトリからの相対パス名を指定する簡略な方法を提供します~。
エスケープキーは、現在のコマンドラインの末尾にファイル名の候補を表示するために、対話的に使用できます。
cdpath は、(change directory) コマンドに検索パスの概念を拡張します。指定されたディレクトリが現在のディレクトリcdにない場合、csh は cdpath ディレクトリ内でそのディレクトリを探します。
1980年代に入っても、ほとんどのユーザーは複数のウィンドウを開くことができないシンプルな文字モード端末しか持っていなかったため、一度に1つのタスクしか処理できませんでした。Cシェルのジョブ制御機能を使うと、現在の作業を中断して、ジョブと呼ばれるCシェルの新しいインスタンスを作成することができました^Z。ユーザーは、コマンドを使ってジョブを切り替えることができました。アクティブなジョブはフォアグラウンドにあると言われ、その他のジョブは中断(停止)されているか、バックグラウンドfgで実行されていると言われました。
パスハッシュは、C シェルの実行可能ファイルの検索を高速化します。C シェルは、各パス ディレクトリでファイルシステム呼び出しを 1 つずつ実行してファイルが見つかるか、可能性のある場所がなくなるまで続けるのではなく、パス ディレクトリをスキャンして構築された内部ハッシュ テーブルを参照します。このテーブルは通常、検索することなく C シェルにファイル (存在する場合) の場所を教えることができ、コマンドで更新できますrehash。
Cシェルは一度に1行ずつ処理します。各行は、スペースまたは括弧、パイプ演算子、入出力リダイレクト演算子、セミコロン、アンパサンドなどの特別な意味を持つ文字で区切られた単語の集合にトークン化されます。
基本的なステートメントとは、単にコマンドを実行するステートメントのことです。最初の単語は実行するコマンドの名前として扱われ、内部コマンド(例:)echoまたは外部コマンドのいずれかになります。残りの単語はコマンドへの引数として渡されます。
基本的な文レベルでは、この文法には以下のような特徴があります。
Cシェルは、すべてのUnixシェルと同様に、ワイルドカード文字を含むコマンドライン引数をパターンとして扱い、一致するすべてのファイル名のリストに置き換えます(グロビングを参照)。
*任意の数の文字に一致します。?任意の1文字に一致します。[…]は角括弧内の任意の文字に一致します。範囲指定はハイフンを使用して行います。[^…セットに含まれていない]任意の文字と一致します。Cシェルはまた、いくつかの表記上の利便性(拡張グロビングと呼ばれることもある)を導入し、それは他のUnixシェルにも模倣された。
abc{def,ghi}は交替(別名ブレース展開)であり、 abcdef abcghiに展開されます。~これは、現在のユーザーのホームディレクトリを意味します。~userユーザーのホームディレクトリを意味します。複数のディレクトリレベルのワイルドカード(例:「*/*.c」)がサポートされています。
バージョン 6.17.01 以降、zshでの再帰的なワイルドカード(例 " **/*.c" または " ***/*.html") もオプションでサポートされていますglobstar。
シェルにワイルドカードの解釈を任せることは、Unix において重要な決定でした。これは、ワイルドカードがすべてのコマンドで常に同じように機能することを意味していました。しかし、この決定は、 csh がコマンドを実行するために使用するexecシステムコールを介して長い引数リストを効率的に渡す Unix の機能に依存していました。対照的に、Windowsでは、ワイルドカードの解釈は従来、各アプリケーションによって行われます。これは、アプリケーションに渡せるコマンドラインが 128 バイトまでだった MS-DOS の名残であり、DOS コマンドプロンプトによるワイルドカードの使用は非現実的でした。最新のWindowsでは、約 32K 文字のUnicodeコマンドラインを渡すことができますが、ワイルドカードの解釈の負担は依然としてアプリケーションにあります。
デフォルトでは、csh がコマンドを実行すると、コマンドは csh の標準入出力 ( stdin)、標準出力 (stdout)、標準エラー (stderr)のファイルハンドルを継承します。これらのファイルハンドルは通常、C シェルが実行されているコンソールウィンドウを指しています。入出力リダイレクト演算子を使用すると、コマンドは入力または出力にファイルを使用するように変更できます。
> fileこれは、標準出力がファイルに書き込まれることを意味します。ファイルが存在する場合は上書きされ、存在しない場合は新規作成されます。エラーは引き続きシェルウィンドウに表示されます。>& fileこれは、標準出力と標準エラー出力の両方がファイルに書き込まれ、ファイルが存在する場合は上書きされ、存在しない場合は作成されることを意味します。>> fileこれは、標準出力がファイルの末尾に追加されることを意味します。>>& fileこれは、stdout と stderr の両方がファイルの末尾に追加されることを意味します。< file標準入力はファイルから読み込まれることを意味します。<< stringこれはヒアドキュメントです。標準入力は、文字列に一致する行まで次の行を読み込みます。サブシェルを使わずに標準エラー出力をリダイレクトすることは不可能です。
set filter = "$home" '/filter' mkfifo "$filter" cat "$filter" & ( ( ls /root/ || echo No access. ) > "$filter" ) >& /dev/null ファイルディスクリプタをファイルとしてサポートするシステムでは、以下の回避策を利用できます。
( ( ( echo ok ; '' ) > /dev/fd/0 ) >& /dev/null < /dev/fd/1 ) | ( echo "$<" bye )複数のコマンドを同じ行に記述できます。
;つまり、最初のコマンドを実行してから、次のコマンドを実行するということです。&&これは、最初のコマンドを実行し、それが0の戻りコードで成功した場合は、次のコマンドを実行することを意味します。||これは、最初のコマンドを実行し、それがゼロ以外の戻りコードで失敗した場合は、次のコマンドを実行することを意味します。コマンドはパイプを使って接続することができ、これにより、あるコマンドの出力が次のコマンドの入力に渡されます。両方のコマンドは同時に実行されます。
|これは、次のコマンドの標準出力を標準入力に接続することを意味します。エラーは引き続きシェルウィンドウに表示されます。|&これは、次のコマンドの標準出力と標準エラー出力の両方を標準入力に接続することを意味します。同時実行とは「並列実行」を意味します。マルチコア(複数プロセッサ)システムでは、パイプで接続されたコマンドは文字通り同時に実行される可能性がありますが、そうでない場合は、オペレーティングシステムのスケジューラがコマンドを時間的に分割して実行します。
例えば「 」というコマンドが与えられるとa | b、シェルはパイプを作成し、 と の両方を起動しますa。2bつのコマンドの標準入出力はリダイレクトされるため、 はa標準出力をパイプの入力に書き込み、bは標準入力をパイプの出力から読み取ります。パイプはオペレーティングシステムによって一定量のバッファリングで実装されているため、 はaパイプがいっぱいになるまでしばらく書き込むことができますが、パイプがいっぱいになると、 がb新しい書き込みをブロック解除するのに十分なデータを読み取るまで、新しい書き込みは OS 内でブロックされます。 が利用可能なデータよりも多くのデータを読み取ろうとすると、がさらにデータを書き込むか、 が終了してパイプが閉じられるまでbブロックされます。aa
単語にドル記号「$」が含まれている場合、それに続く文字は変数名として扱われ、参照はその変数の値に置き換えられます。参照の末尾に付加されるさまざまな編集演算子を使用すると、パス名の編集(例:「:e」で拡張子のみを抽出)やその他の操作が可能です。
引用機能を使うと、空白文字、ワイルドカード、括弧、ドル記号など、通常は特殊文字として扱われる文字を、文字通りのテキストとして扱うことができます。
\次の文字を通常の文字として扱うことを意味します。"文字列は"弱い引用符で囲まれています。囲まれた空白文字とワイルドカードはリテラルとして扱われますが、変数とコマンドの置換は引き続き実行されます。'string'は強い引用符です。囲まれた文字列全体がリテラルとして扱われます。二重引用符の中に二重引用符がある場合は、エスケープする必要があります"\""。ドル記号についても同様で、変数展開を防ぐためです"\$"。バッククォートについては、コマンド置換のネストを防ぐため、シングルクォートが必要です"'\`'"。
コマンド置換機能を使うと、あるコマンドの出力を別のコマンドの引数として使用できます。
`コマンドとは、コマンド`の出力を取得し、それを単語に解析して、コマンドラインに貼り付けることを意味します。以下は、リーニング・トゥースピック症候群によるネストされたコマンド置換の例です。
echo "`エコー " \"\` "エコー " \"\\\"\\\`\" "エコー " \"\\\"\\\\\\\"\\\\\\\`\\\"\" "エコー " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\`\\\\\\\"\\\"\" "エコー " \"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\`\\\\\\\\\\\\\\\"\\\\\\\"\\\"\" "pwd" \"\\\"\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ `通常、Cシェルはコマンドを開始すると、コマンドが終了するまで待機してから、新しいコマンドを入力できることを示す別のプロンプトをユーザーに表示します。
&を開始し、すぐに新しいコマンドの入力を求めることを意味します。サブシェルとは、シェルの独立した子コピーであり、現在の状態を継承しますが、親シェルに影響を与えることなく、例えば現在のディレクトリを変更するなど、変更を加えることができます。
( コマンドとは、サブシェル内でコマンド )を実行することを意味します。Cシェルは、条件判定と反復処理の両方に対応する制御構造を提供します。条件判定の制御構造はif文とswitch文です。反復処理の制御構造はwhile文、foreach文、repeat文です。
if文には2つの形式があります。短縮形は1行で記述できますが、式が真の場合に指定できるコマンドは1つだけです。
if (式)コマンド 長い形式では、then、else、endif キーワードを使用して、条件の中にコマンドのブロックをネストできるようにします。
if ( expression1 ) then commands else if ( expression2 ) then commands ... elseコマンド endifelse と if のキーワードが同じ行にある場合、csh はそれらをネストするのではなく、連鎖させます。ブロックは単一の endif で終了します。
switch文は、文字列をパターンリスト(ワイルドカード文字を含む場合もある)と比較します。一致するパターンがない場合は、デフォルトのアクション(存在する場合)が実行されます。
switch ( string ) case pattern1: コマンド breaksw ケースパターン2: コマンド ブレイクス ... デフォルト: コマンド breaksw endswwhile文は式を評価します。式が真であれば、シェルはネストされたコマンドを実行し、式が真である限り繰り返します。
while (式) コマンド 終わりforeach文は値のリスト(通常はワイルドカードによって生成されたファイル名のリスト)を受け取り、それぞれの値に対してループ変数をその値に設定し、ネストされたコマンドを実行します。
foreachループ変数(値のリスト) コマンド 終わりrepeat文は、単一のコマンドを整数回繰り返します。
整数コマンド を繰り返すCシェルはシェル変数と環境変数の両方を実装しています。[ 13 ]ステートメントを使用して作成された環境変数はsetenv常に単純な文字列であり、子プロセスenvp[]に渡され、子プロセスは引数を介してこれらの変数を取得しますmain()。
set`or`文を使用して作成されるシェル変数は@、Cシェル内部の変数です。子プロセスには渡されません。シェル変数は、単純な文字列または文字列の配列のいずれかになります。シェル変数の中には、あらかじめ定義されており、Cシェルのさまざまな内部オプションを制御するために使用されます。たとえば、ワイルドカードが何も一致しなかった場合の動作などです。
現在のバージョンのcshでは、文字列の長さは任意で、数百万文字に及ぶこともあります。
変数は必要に応じて拡張できます。ただし、固定サイズで作業したい場合は、以下の構文を使用することをお勧めします。
# 1024個の要素を格納できる十分な大きさの変数を作成します。set fixed = { , }{ , }{ , }{ , } { , }{ , }{ , }{ , }{ , }{ , }Cシェルは、Cから借用した演算子に加え、文字列比較やファイルシステムテスト(ファイルの存在確認など)のための追加演算子を備えた32ビット整数式文法を実装しています。演算子はオペランドから空白で区切る必要があります。変数は$名前の形式で参照されます。
演算子の優先順位もC言語から借用されていますが、同じ優先順位の演算子が連続する場合の曖昧さを解消するために、演算子の結合規則が異なります。C言語では、ほとんどの演算子の結合規則は左から右ですが、Cシェルでは右から左です。例えば、
// C は左からグループ分けしますint i = 10 / 5 * 2 ; printf ( "%d \n " , i ); // 4 と出力されますi = 7 - 4 + 2 ; printf ( "%d \n " , i ); // 5 と出力されますi = 2 >> 1 << 4 ; printf ( "%d \n " , i ); // 16 と出力されます# Cシェルは右からグループ化します @ i = 10 / 5 * 2 echo $i # 1 と出力します @ i = 7 - 4 + 2 echo $i # 1 と出力します @ i = ( 2 >> 1 << 4 ) echo $i # 0 と出力しますCシェルの例にある括弧は、ビットシフト演算子が入出力リダイレクト演算子と混同されるのを防ぐためのものです。どちらの言語でも、括弧は評価の順序を明示的に指定するために常に使用できます。これは、単に分かりやすくするためだけでも有効です。
戻り値は8ビットに制限されます。exit式の場合、32ビットでの評価には単項否定演算子を使用できます。
exit !! 256 # 1 を返します。スティーブン・ボーン自身は、対話的な使用においてはcshが彼のシェルよりも優れていると認めていたが、 [ 14 ]スクリプト作成においてはそれほど人気がなかった。
1983年には、ベル研究所のライセンスの下、チャールズ・リバー・データ・システムズのUNOSオペレーティングシステムをはじめとするUNIXツールでcshとBourneシェルが利用可能になった。[ 15 ]
当初、そして1980年代を通じて、cshはすべてのUnixおよびUnixライクなシステムに存在することが保証されていませんでしたが、shは存在していたため、他のマシンで実行する必要のあるスクリプトにはshの方が適していました。1990年代半ばまでにcshは広く利用可能になりましたが、スクリプトにcshを使用することはPOSIX委員会から新たな批判に直面しました[ 16 ] 。POSIX委員会は、対話型とスクリプトの両方の目的で、 KornShellという1つの推奨シェルのみが存在するべきであると規定しました。Cシェルは、構文の欠陥、機能の欠如、実装の不備などについて、他の人々からも批判を受けました[ 17 ] [ 18 ] 。
setおよびsetenvコマンドaliasはすべて基本的に同じこと、つまり、名前を文字列または単語のセットに関連付けるという動作をする。しかし、これら3つにはわずかだが不必要な違いがあった。には等号が必要だったが、やには不要だった。には単語リストを括弧でset囲むsetenv必要aliasがあったが、setやには不要だったsetenv、aliasなど。同様に、、、ifおよびswitchループ構造では、ネストされたブロックを終了するために、不必要に異なるキーワード( endif、endswおよびend)が使用されている。ほとんどの対話型コマンドでは問題なく動作しましたが、ユーザーがスクリプトに記述するような複雑なコマンドでは、容易に失敗し、意味不明なエラーメッセージが表示されるか、望ましくない結果が生じる可能性がありました。たとえば、Cシェルは制御構造間のパイプをサポートしていませんでした。foreachコマンドの出力をパイプで渡そうgrepとしても、単純に機能しませんでした。(パーサーに関する多くの問題に対する回避策は、コードを複数のスクリプトに分割することです。をforeach別のスクリプトに移動すると、スクリプトは正しいstdioハンドルを継承する新しいcshのコピーをフォークして実行されるため、パイプが機能します。単一ファイル内でコードを分割することも可能です。単一ファイル内でコードを分割する方法の例を以下に示します。)
別の例として、以下のコード断片に見られる好ましくない動作が挙げられます。どちらも「'myfile'が存在しない場合は、'mytext'を書き込んで作成する」という意味に見えます。しかし、右側のバージョンは常に空のファイルを作成します。これは、Cシェルの評価順序が、各コマンド行を読み込んだ際に、まず入出力リダイレクト演算子を探して評価し、その後で残りの行を調べて制御構造が含まれているかどうかを確認するためです。
# 期待どおりに動作しますif ( ! -e myfile ) then echo mytext > myfile endif # 常に空のファイルを作成するif ( ! -e myfile ) echo mytext > myfile # 回避策 (tcsh のみ) if ( ! -e myfile ) eval "echo mytext > myfile"# 2 番目の回避策 (csh および tcsh 用) ( exit ( -e myfile ) && ( ( echo mytext > myfile ) >& /dev/null || echoファイルを作成できません。) || echoファイルが存在します。 また、この実装は、例えば「0: イベントが見つかりません。」のように、問題に関する有用な情報を一切提供しない、非常に不十分なエラーメッセージについても批判されている。
しかし、練習を重ねることで、これらの欠点を克服することが可能です(つまり、プログラマーはスクリプトを実装する際に、より適切で安全なアプローチを取るようになります)。
「0: イベントが見つかりません」というエラーは、履歴に保存されたコマンドがないことを意味します。スクリプトでは履歴が正しく機能しない場合があります。その場合は、あらかじめコマンドを変数に格納しておくことで回避できます。
#!/bin/csh -f set cmdlist = ( 'date # 1' \ 'uname # 2' \ 'tty # 3' \ 'id # 4' ) echo -n '履歴からコマンドを実行する番号を入力してください: ' set cmdexec = "$<" ( exit ( ! ( "$cmdexec" > 0 && \ "$cmdexec" < = "$#cmdlist" ) ) ) >& /dev/null if ( "$status" ) then echo '無効なイベント番号です。' foreach cmd ( $cmdlist :q ) echo "$cmd" end exit -1 endif eval "$cmdlist[$cmdexec]"関数の回避策として、スクリプトを再帰的に実行することでコードを壊すことを好みます。
#!/bin/csh -f if ( ! "$?main" ) then if ( ! "$?0" ) then echo 'このスクリプトは、明示的にファイルを呼び出すことで実行する必要があります。' exit -1 endif alias function 'set argv = ( \!* ) ; source "$main"' set main = "$0" set ret = "`function myfunc`" echo "$ret" exit endifgoto "$1" ; shift myfunc: 関数 myfunc2 echo "関数です。" exit myfunc2: echo "別の関数です。" exit
Cシェルは、履歴機能、エイリアス、チルダ表記、対話型ファイル名補完、シェルに組み込まれた式文法など、数多くの革新的な機能を導入することに非常に成功し、それらはその後他のUnixシェルにも模倣されました。しかし、 kshやbashなど、多数の独立したクローンを生み出したshとは対照的に、cshのクローンは2つしか知られていません。( tcshはBill Joyが最初に書いたcshのコードに基づいているため、クローンとはみなされません。)
1986年、アレン・ホルブは『On Command: Writing a Unix-Like Shell for MS-DOS』[ 21 ]を執筆した。この本は、彼が書いた「SH」というプログラムについて説明しているが、実際にはshではなくcshの言語設計と機能をコピーしたものだった。SHの完全なソースコードと基本的なUnixライクなユーティリティ(cat、cp、grepなど)のソースコードを含む付属のフロッピーディスクが、それぞれ25ドルと30ドルで出版社から入手できた。ホルブのSHの制御構造、式文法、履歴メカニズム、その他の機能は、Cシェルのものと全く同じだった。
1988 年、Hamilton Laboratories はOS/2用のHamilton C シェルを出荷し始めました。[ 22 ]これには csh クローンと Unix ライクなユーティリティのセットの両方が含まれていました。1992 年に、Hamilton C シェルはWindows NT用にリリースされました。[ 23 ] Windows 版は現在も積極的にサポートされていますが、OS/2 版は 2003 年にサポートが終了しました。[ 23 ] 1990 年初頭のクイック リファレンス[ 24 ]では、その意図は「ジョブ制御を除く C シェル言語全体に完全に準拠すること」でしたが、言語設計の改善と Unix と PC の違いへの適応が行われました。最も重要な改善は、制御構造をネストまたはパイプできるトップダウン パーサーでした。これは、アドホック パーサーを使用していたオリジナルの C シェルではサポートできませんでした。Hamilton はまた、組み込みおよびユーザー定義のプロシージャ、ブロック構造のローカル変数、浮動小数点演算などの新しい言語機能を追加しました。 PCへの適応には、PC上のファイル名やその他の規則のサポート、および並列処理を実現するためにフォーク(OS/2やWindowsでは利用できなかった)の代わりにスレッドを使用すること(例えば、パイプラインの設定など)が含まれていました。
2026年、TropibyteはC Shell for Windows(cshw)をリリースした。これはCygwinやWSLに依存しないネイティブWin32 csh実装である。Hamilton Cシェルと同様に、フォークベースの並列処理を避け、代わりにコルーチンとWindows同期プリミティブを使用している。[ 25 ]