Linux 学习笔记(十四)—— 简易shell实现

// makefile
myshell:myshell.c
    gcc -o $@ $^ -std=c99
.PHONY:clean
clean:
    rm -f myshell
// myshell.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define LINE_SIZE 1024
#define ARGV_MAX
#define DELIM " "
#define EXIT_CODE 65

int quit = 0;
int last_code = 0;
char PWD[LINE_SIZE];
char myenv[LINE_SIZE];

char command_line[LINE_SIZE];

const char* getusername()
{
return getenv("USER")
}

const char* gethostname()
{
return getenv("HOSTNAME")
}

void getpwd()
{
 getcwd(PWD, sizeof(PWD));
}

void Interact(char *command_line, int size)
{
printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(),  gethostname(),PWD);
\\ scanf("%s", command_line);此处不能用scanf()因为该函数读到第一个空格就停止了,读不到选项
fgets(command_line, size, stdin);
command_line[strlen(command_line) - 1] = '\0';  \\ 把最后的‘\n’去掉;
return;
}

int splitstring(char* argv[], char *command_line)
{
int i = 0;
argv[i++] = strtok(command_line, DELIM)
while(argv[i++] = strtok(NULL, DELIM));
return i-1;
}

void normalexcute(char* argv)
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return;
    }
    if(id == 0)
    {
        //子进程
        execvpe(argv[0], argv, environ);
        exit(EXIT_CODE);
    }else
    {
        //父进程等待
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);
        if(rid == id)
        {//等待成功了
        last_code = WEXITSTATUES(status);
    }
    }
}

int buildinf(int argc, char* argv)
{
    if(argc == 2 && strcmp(argv[0], "cd") == 0)
    {
        chdir(argv[1]);
        getpwd();
        sprintf(gentenv("PWD", "%s", PWD));
        continue;
        return 1;
    }
    if(strcmp(argv[0], "export") == 0)
    {
        // putenv(argv[1]);
        // 此处有误,在于putenv()只是修改了环境变量的指针,而没有提供存储位置
        // 如果argv内存改变,之前putenv()的环境变量也会被改变
        strcpy(myenv], argv[1]);
        putenv(myenv);
        //此处只能有一个环境变量,进一步修改省略;
        return 1;
    }
    if(argc == 2 && strcmp(argv[0], "echo") == 0)
    {
        if(strcmp(argv[1], "$?") == 0)
        {
            printf("%d\n", last_code);
            last_code = 0;
        }
        else if(*argv[1] == '$')  
        {
            char* val = getenv(argv[1]+1);
            if(val)  printf("%s\n", val);
        }
        else printf("%s\n", argv[1]);
        return 1;
    }

    //特殊处理颜色
    if(strcmp(argv[0], "ls") == 0)
    {
        argv[argc++] = "--color";
        argv[argc] = NULL;
    }
return 0;
}

main()
{
extern char** environ;
char command_line[LINE_SIZE];
char* argv[LINE_SIZE] = {NULL};

while(quit)
{
    Interact(command_line, sizeof(command_line));
    int argc = splitstring(argv, command_line);
    if(argc == 0) continue;
    if(1 == buildinf(argc, argv)) continue;
    normalexcute(argv);


}
return 0;
}

#include <stdio.h>

char* fgets(char* s【指向存储位置,存储从文件中读取的信息】, int size【指定最多读取的字符数,包括换行和文件结束标志】, FILE* stream【文件指针,表示要从哪个文件中读取数据】);   

——  成功返回字符串起始地址,失败返回NULL

功能:输入字符或字符串

标准文件流:FILE* stdin、FILE* stdout、FILE* stderr

#include <string.h>

char* strtok(char* str 【指向要分割的字符串的指针。在第一次调用 strtok 时,这个参数是必须的。在后续调用中,如果为 NULL,则 strtok 会继续处理上次调用时的字符串。】, const char* delim 【指向分隔符集合的指针。这个字符串中的每个字符都是一个分隔符,用于分割 str 字符串】);  ——  extract tokens from strings

#include <unistd.h>

int chdir(const char* path);      ——  change working directory

#include <stdio.h>

sprintf(char* str【字符数组的指针,这个数组将存储格式化后的输出字符串】, const char* format, ...【可变参数列表,这些参数根据格式字符串中的格式说明符进行相应的格式化】); 

#include <unistd.h>   系统调用,获取当前工作路径

char* getcwd(char* buf 【是一个字符数组,用于存储当前工作目录的路径】, size_t size【 buf 数组的大小】); 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值