Linux用のシンプルなシェルコマンドラインインタープリタ

目次

1. 基本原則

2. コードの実装


これまでにプロセスの作成、プロセスの終了、プロセスの待機、プロセスの置換について学習し、これらの内容を通じて、単純なシェル コマンド ライン インタプリタを実装できます。シェルコマンドラインインタープリターの実装方法を直接見てみましょう。

1. 基本原則

1. シェル インタープリタを開いた後は、自分で閉じない限り決して終了しないことがわかっているため、コマンド ライン インタープリタは無限ループになるはずです。

2. 入力: コマンドラインの前の行の内容を取得し、fgets 関数を使用してそれを取得する必要がありますが、同時に cmd_line[NUM] 配列を定義して、ユーザーが入力した内容を保存することができます。

3. 解析: 入力後、当然文字列を解析する必要があります。文字列を分割し、コマンド + オプションとその他の内容に分割する必要があります。ここでは、strtok 関数を使用して文字列をいくつかの部分文字列に切り分け、それぞれを分離します。の部分文字列は char* g_val[SIZE] 配列に保存されます。strtok: 初めてパラメータを直接渡し、2 回目には NULL を渡す必要があります。そして最終的に strtok は NULL を返します。

4. コマンドを入力した後、インターフェイスは同じままであることがわかります。これは、親プロセスがコマンドの実装を支援するために子プロセスを作成し、親プロセスは子プロセスが終了して戻るのを待つ必要があるためです。結果。

5. 子プロセスがコマンドを実行するとき、プロセス置換の知識を使用して、コードをコマンドによって実行されるコードに置き換える必要があります。

6. cd コマンドなどの一部のコマンドは、完了を子プロセスに任せると、子プロセスのパスのみが変更されるため、cd コマンドは親プロセスによって完了する必要があります。

実行用のサブプロセスを作成する必要はなく、シェルにコマンドを単独で実行させます (これを組み込みコマンドと呼びます)。本質はシステム インターフェイスを実行することであり、システム インターフェイスを chdir と呼び、親プロセスが独自にパスを変更できるようにします。

7. コマンドを入力した後、通常は Enter キーを押して実行しますが、fgets はそれを入力文字として扱い、結果をユーザーに提示するときに、前の行の次ではなくもう 1 行に変更します。結果を表示します。したがって、次のことを行う必要があります。

cmd_line[strlen(line_cmd)-1] = '\0';

8. 別の例として、ll のようなコマンドは ls -l と同等なので、配列 char* g_val[SIZE] を g_val[0] = "ls", g_val[1] = " -l に置き換える必要があります。 「」で十分です。

2. コードの実装

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<unistd.h>

#define NUM 32
#define SIZE 1024
#define SEP " "
char cmd_line[NUM];//存放输入的字符串
char* g_val[SIZE];//存放解析出来的字符串

int main()
{
    //命令行解释器是一个不退出的进程
    while(1)
    {
       printf("[zdl@hcss-ecs-d14f ~]# ");
       fflush(stdout);
       memset(cmd_line, '\0', sizeof(cmd_line));

       if(fgets(cmd_line,sizeof(cmd_line),stdin) == NULL)
       {
           continue;
       }
       cmd_line[strlen(cmd_line)-1] = '\0';

       //命令行字符解析
       g_val[0] = strtok(cmd_line, SEP);
       int index = 1;
       if(strcmp(g_val[0],"ll")==0)
       {
           g_val[0]="ls";
           g_val[index++]="-l";
       }
       while(g_val[index++] = strtok(NULL, SEP));//如果还解析原字符串,就传入NULL
       
       //让父进程执行的命令叫做内置命令
       if(strcmp(g_val[0], "cd")==0)
       {
           if(g_val[1] != NULL)
               chdir(g_val[1]);

           continue;
       }

       //创建子进程去执行
       pid_t id = fork();
       if(id==0)
       {
           execvp(g_val[0], g_val);
           exit(1);
       }

       //父进程
       int status = 0;
       pid_t ret = waitpid(id, &status,0);
       if(ret > 0)
       {
           printf("exit code: %d\n",WEXITSTATUS(status));
       }
    }

    return 0;
}

コードを実行した結果は次のようになります。

おすすめ

転載: blog.csdn.net/zdlynj/article/details/134828406