1. 程式人生 > >Linux下的簡易shell實現

Linux下的簡易shell實現

  • Linux系統的shell作為作業系統的外殼,為使用者提供使用作業系統的介面。
  • 它是命令語言、命令解釋程式及程式設計語言的統稱。
  • 相當於bash的一個子程序,父程序等待,子程序進行程式替換。
  • shell充當一個橋樑:將使用者的命令翻譯給核心(kernel)處理;同時,將核心的處理結果翻譯給使用者。
  • shell在你成功地登入進入系統後啟動,並始終作為你與系統核心的互動手段直至你退出系統。
  • 你係統上的每位使用者都有一個預設的shell,每個使用者的預設shell在系統裡的/etc/passwd檔案裡被指定。

寫一個簡易的shell需要以下操作:

  1. 獲取命令列
  2. 解析命令列(strtok:將字串打散)
  3. 建立一個子程序(fork)
  4. 替換子程序(execve)
  5. 父程序等待子程序(wait)

程式碼實現:

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

int main()
{
        while(1)
        {
                printf("[Myshell]>");
                fflush(stdout);
                //解析輸入到shell上的字串 ls   -a -l
                char buffer[1024];
                int read_size = read(1, buffer, sizeof(buffer)-1);
                if (read_size > 0)
                {
                        buffer[read_size - 1] = 0;
                }
                char* shell_argv[32] = {NULL};
                int shell_index = 0;
                char* start = buffer;
                while (*start != '\0')
                {
                        while (*start != '\0' && isspace(*start))
                        {
                                start++;
                        }
                }

                //建立子程序來exec

                pid_t pid = vfork();

                if (pid < 0)
                {
                        printf("vfork failure\n");
                        exit(1);
                }
                else if (pid == 0)
                {
                //考慮重定向 > 
                //在字串陣列中找重定向標誌
                        int i = 0;
                        int flag = 0;
                        for (; shell_argv[i] != NULL; ++i )
                        {
                                if (strcmp(">", shell_argv[i]) == 0)
                                {
                                        flag = 1;
                                        break;
                                }
                        }

                        int copyFd;
                        shell_argv[i] = NULL;
                        if (flag)
                        {
                                if (shell_argv[i+1] == NULL)
                                {
                                        printf("command error\n");
                                        exit(1);
                                }
                                close(1);
                                int fd = open(shell_argv[i+1], O_WRONLY | O_CREAT, 0777
);
                                copyFd = dup2(1, fd);
                        }
                        execvp(shell_argv[0], shell_argv);
                        if (flag)
                        {
                                close(1);
                                dup2(copyFd, 1);
                        }
                        exit(1);
                }
                else //father process
                {
                        int status = 0;
                        int ret = waitpid(pid, &status, 0);
                        if (ret == pid)
                        {
                                if (WIFEXITED(status))
                                {
                                        // printf("exitCode is %d\n", WEXITSTATUS(statu
s));
                                }
                                else if (WIFSIGNALED(status))
                                {
                                        printf("signal is %d\n", WTERMSIG(status));
                                }
                        }
                }
        }
        return 0;
}