web-dev-qa-db-ja.com

基本的なシェルを書く

私のクラスでは、bashに似た基本的なシェルを作成して、ユーザーがls、sleepなどのコマンドを呼び出せるようにする必要があります。これを行う方法に関するリソースを探しています。チュートリアル、ヘルプテキスト、サンプルコード、開始方法に関する一般情報。誰かが私を助けるためのリンクや情報を持っていますか?

21
Bobby S

Glibcのマニュアルには、シェルでのジョブ制御の実装に関する有用な情報が含まれています。 http://www.gnu.org/software/libc/manual/html_node/Implementing-a-Shell.html#Implementing-a-Shell

24

それは本当にあなたのシェルがいかに単純でなければならないかに依存します。ジョブ制御(つまり、バックグラウンド処理)やパイプが必要ない場合は、非常に簡単です。以下に例を示します。

#include <stdio.h>
#include <stdlib.h>

#define MAX_LENGTH 1024

int main(int argc, char *argv[]) {
  char line[MAX_LENGTH];

  while (1) {
    printf("$ ");
    if (!fgets(line, MAX_LENGTH, stdin)) break;
    system(line);
  }

  return 0;
}

CTRL-Dで上記の例を終了できます。 exitcdなどの組み込みコマンドを追加するには、strtok()を使用して行をトークン化し、最初のトークンを確認する必要があります。これらのコマンドが追加された、より複雑な例を次に示します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef _WIN32
#include <windows.h>
#define chdir _chdir

#else
#include <unistd.h>
#endif

#define MAX_LENGTH 1024
#define DELIMS " \t\r\n"

int main(int argc, char *argv[]) {
  char *cmd;
  char line[MAX_LENGTH];

  while (1) {
    printf("$ ");
    if (!fgets(line, MAX_LENGTH, stdin)) break;

    // Parse and execute command
    if ((cmd = strtok(line, DELIMS))) {
      // Clear errors
      errno = 0;

      if (strcmp(cmd, "cd") == 0) {
        char *arg = strtok(0, DELIMS);

        if (!arg) fprintf(stderr, "cd missing argument.\n");
        else chdir(arg);

      } else if (strcmp(cmd, "exit") == 0) {
        break;

      } else system(line);

      if (errno) perror("Command failed");
    }
  }

  return 0;
}

さらにビルドコマンドを追加するか、ホームディレクトリに変更するための引数なしでcdのようなものをサポートすることでこれを拡張できます。現在のディレクトリなどの情報を追加して、コマンドプロンプトを改善することもできます。

サイドノートとして、コマンド履歴と行編集機能を追加する簡単な方法は、GNU readlineライブラリを使用することです。

10
jcoffland

HelenOSプロジェクト 用の非常に基本的なシェルを作成しました。次の機能があります。

  • 行編集/履歴
  • コマンド/ロード可能なコマンドのBuit
  • 外部コマンドを見つけるための検索パス
  • 極めて基本的なスクリプト
  • 組み込み関数としてのほとんどのGNUコアユーティリティ(ゼロから作成)の実装をバカにした。

そのほとんどは、関数ポインタを中心に構築された非常にシンプルで再利用可能なフレームワークに実装されています。少なくとも、誰かが実際にシェルから抜け出すことができるように、「cd」と「pwd」に加えて、組み込みの「exit」または「quit」が必要です。組み込みの「エクスポート」/「宣言」も意味があります。

こちら でライセンスされているコード(BSD)を見ることができます。または、リポジトリをダウンロードします。それはuspace/app/bdshにあります。必要に応じて移植する前に、おそらく最後に動作するLinuxバージョンを掘り下げることができます。最大の違いは、HelenOSバージョンではexecve()/ posix_spawn()などの代わりに自家製の行エディターtask_spawn()を使用していることです。残りは移植可能です。元々、機能のテストを簡単かつインタラクティブにするためだけに設計されました。ジョブ制御は必要ないため、実装しませんでした。ただし、それは簡単に実現できます。

「本物の」シェルを勉強したい場合は、dashを確認することを強くお勧めします。bashのコードに直接飛び込むよりも、把握する方がはるかに簡単です。

逸話的に、「bdsh」は「brain dead Shell」を表します。

4
Tim Post

開始している場合は、 http://stephen-brennan.com/2015/01/16/write-a-Shell-in-c/ を試してください。詳細な知識については http: //www.gnu.org/software/libc/manual/html_node/Data-Structures.html#Data-Structures

また、C/C++を使用してシェルをプログラムする方法を学びながら、コマンドのマニュアルページを参照する習慣をつけます。

2
Laschet Jain

非常に小さなシェルの実装については、 BusyBox をご覧ください。

2
R..

Bashには、cdpushdpopd、変数処理ルーチン(setおよび_$x_)、およびループや条件などのすべての制御フロー項目。他のほぼすべてのコマンドは_$PATH_にあります。

割り当てに特に明記されていない限り、変数と制御フローを無視します。 [〜#〜] repl [〜#〜] を提供するだけで、_$PATH_を検索し、ユーザーが入力したものを実行します(おそらくposix_spawn()を使用)コマンドライン引数を渡します。

0
chrisaycock

ローボールの答え:

プログラムが非常に単純な場合、コマンド「system("putdesiredcommandhere");」を使用して、単純なシステムコールをスクリプトのように実装できます。

プログラムに「printf」をインストールすると、stdio.hを使用して簡単なシステムコールが実行されます。

小さなコードサンプルが続きます。

#include <stdio.h>
#include <stdlib.h>
main ()
{
    system ("clear");
    system ("echo this is an example of a basic system call");
    printf ("just as you've always done.\n");

    return 0;
}

この方法を使用すると、bashまたはcshスクリプトをcプログラムに転写できます。スクリプトの各行にシステムコールを使用する必要があります。

0
agx