Linux.实现一个简单的shell

  • fork & execve

Shell框架

  • shell start and wait for inputing command and paraments
  • identify the command
  • cannot identify then print ‘bad command’ and go back to wait
  • if exit then exit() shell
  • else fork(), child execve() the Executable file, father wait() for the child

这里写图片描述


实现简单的命令

my_pwd
  • print current working directory
/* 
 * my_pwd.c
 */
#include <unistd.h>
#include <stdio.h>

char curp[255];
void main(int argc,char *argv[])
{
   getcwd(curp,255);
   printf("PWD: %s\n",curp);
   return;
}
my_ls
  • list the directory and regular file contained by the given directory
  • support absolue path and relative path
/*
 * my_ls.c
 *
 */
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
...
char **pths = NULL;    //store the pathes to list
int pth_n = 0;         //the number of paths
...
int res = 0;
struct stat st_f;
DIR* dir = NULL;
struct dirent* dir_ent = NULL;
for(int i = 0; i < pth_n; ++i){
    char pth[255];
    if(pths[i][0] == '/')
        sprintf(pth,"%s",pths[i]);
    else // char cwd[255] & getcwd(cwd,sizeof(cwd))
        sprintf(pth,"%s/%s", cwd, pths[i]);

    res = stat(pth, &st_f);
    if(res < 0){
        printf("cannot stat path %s\n", pth);
        continue;
    }

    if(!S_ISDIR(st_f.st_mode)){
        printf("%s is not a directory\n", pth);
        continue;
    }else{
        dir = opendir( pth );
        if(dir == NULL)
            printf("cannot open ab_path %s\n", pth);

        dir_ent = readdir( dir );
        while( dir_ent != NULL ){
            //ignore ".." "." and ".*" which are hidden files
            if(dir_ent->d_name[0] == '.'){
                dir_ent = readdir( dir );
                continue;
            }

            if(dir_ent->d_type == DT_DIR)
                printf("d %s\n",dir_ent->d_name);
            else if(dir_ent->d_type == DT_REG)
                printf("r %s\n",dir_ent->d_name);

            dir_ent = readdir( dir );
        }
    }
 }
my_cd
  • fork & execve cannnot change father process’s current working directory
  • then chdir() should called by shell itself
/*
 * test_cwd.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

void main(int argc,char**argv)
{
    char cwd[255];
    int cwd_size = sizeof(cwd);
    printf("cwd_size = %d\n", cwd_size);
    getcwd(cwd, cwd_size);
    printf("riginal father cwd = %s\n", cwd );

    pid_t pid = fork();
    if(pid == 0){
        chdir("/home");
        getcwd(cwd, 255);
        printf("child cwd = %s\n", cwd );
    }
    else if(pid > 0){
        wait(pid);
        getcwd(cwd, 255);
        printf("father cwd = %s\n", cwd );
    }
}

MyShell Process

  • void my_exec(char *filename) to fork & execve with the given filename, and father process should wait()
  • int dispatch(char *input) to identify command and paraments, then store them(include cmd and paras) in char* cmd_paras[]
  • void get_input(char *cmd) to read up to 255 charactors from user input
/*
 * my_shell.c
 */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <sys/types.h>

char* cmd_set[] = {"exit","my_cd","my_ls","my_pwd"};
char* cmd_paras[MY_CMD_NUM];
int cmd_paras_n = 0;

char cwd[ MY_CWD_SIZE ];

void my_exec(char *path)
{
    int pid = fork();
    if(pid == 0)        execve(path, cmd_paras, env);
    else if(pid > 0){
        int status = 0;
        pid_t pidd = 0;
        pidd = wait(&status);
    }
    else if(pid < 0)    printf("fail to fork process.\n");
}

int dispatch(char *input)
{
    int ret = -1, res = 0;
...
    //cmd_paras[0] is the command
    //cmd_paras[1..n] are the paramenst
    //cmd_paras_n = n+1
    if(!strcmp(cmd_paras[0], cmd_set[0])) ret = 0;   //exit
    if(!strcmp(cmd_paras[0], cmd_set[1])){           //cd
        ret = 1;
        char dir[MY_CWD_SIZE];
        if(cmd_paras_n == 1){
            uid_t usrid = getuid();
            struct passwd* pwd = getpwuid(usrid);
            sprintf(dir, "/home/%s", pwd->pw_name);
        }
        else{
            char* new_cwd = cmd_paras[1];
            if(new_cwd[0] == '/') sprintf(dir, "%s", new_cwd);
            else sprintf(dir, "%s/%s", cwd, new_cwd);
        }
        res = chdir(dir);
        if(res < 0)printf("failed to change cwd to %s\n",dir);
        }
    if(!strcmp(cmd_paras[0], cmd_set[2])) ret = 2;  //ls
    if(!strcmp(cmd_paras[0], cmd_set[3])) ret = 3;  //pwd

    return ret;
}

void get_input(char *cmd)
{
    int i = 0;
    char c = getchar();
    while( c != '\n' && i < 255 ){
        cmd[ i++ ] = c;
        c = getchar();
    }
    cmd[ i ] = '\0';
}

void main(int argc,char **argv)
{
    char cmd[ MY_CMD_SIZE ];
    const char * cmd_path = "/home/niugen/LINUX_CLASS";

    int cmd_n = 0, loop = 1;

    char cmd_file[ MY_CMD_SIZE ];
    while(loop){
        getcwd(cwd, MY_CWD_SIZE);
        printf("MyShell@%s > ", cwd);
        get_input( cmd );

        cmd_n = dispatch( cmd );

        if(cmd_n < 0)printf("Bad Command.\n");    //bad command
        else if(cmd_n == 0) loop = 0;             //exit
        else if(cmd_n != 1){                      //not 'cd'
            sprintf(cmd_file,"%s/%s", cmd_path, cmd_paras[0]);
            my_exec(cmd_file);
        }
    }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值