早点打完工去睡觉

早点打完工去睡觉

目录

一、Mybash介绍

1.1.mybash.c

    打印函数

    分割函数

    命令函数

二、Mybash实现

2.1.打印函数

2.1.1需要使用到的功能函数

1.获取与当前用户关联的UID

2.获取与当前用户的相关信息---一个结构体(passwd)

3.获取主机信息

4.获取当前所处位置

5.给对应字体加颜色

2.1.2 打印函数实现

2.2 分割函数

2.2.1 strtok函数

2.2.2分割函数实现

 2.3 命令函数

2.3.1 exit

2.3.2 clear

 2.3.3 cd

2.3.4 chmod

2.3.5 pwd

2.3.6 mkdir

2.3.7 rmdir

2.3.8 rm

2.3.9 复制、更新进程

三、使用看效果


一、Mybash介绍

1.1.mybash.c

    这个函数用来实现mybash,可分为三大部分:打印函数、分割函数、命令函数

    打印函数

打印出如下的功能
    Linux Day10 ---Mybash-LMLPHP

能够和bash一样显示出用户+主机名+当前目录+用户身份

    分割函数

将输入的命令按空格分割,并保存到相应的数组中,使用到strtok()字符分割函数。

    命令函数

根据exec系列学习,采用fork+exec,父进程等待,子进程采用exec,调用自己实现的命令文件,进行真实命令的模拟

二、Mybash实现

2.1.打印函数

2.1.1需要使用到的功能函数

1.获取与当前用户关联的UID

uid_t getuid(void);

如果得到是0,就是管理员,初始为普通用户。

2.获取与当前用户的相关信息---一个结构体(passwd)

 struct passwd*getwuid(uid_t uid);

这里可以定义一个相对应类型的指针ptr去指向该结构体,进而->方式访问到该用户的UID号

3.获取主机信息

int gethostname(char*name,size_t namelen);

gethostname函数把机器的主机名写入到name字符串里,该字符串至少有namelen个字符长。而成功,gethostname的返回0,否则返回-1。

4.获取当前所处位置

char*getcwd(char*buf,size_t size);

getcwd函数把当前目录的名字写入给定的缓冲区-buf,如果目录名长度超出参数size给出的缓冲区长度,就返回NULL,如果成功,返回指针buf。

5.给对应字体加颜色

详细参考printf函数中的/033一系列。

2.1.2 打印函数实现

void print_info()
{
    uid_t uid=getuid();
    char*s="$";
    if(uid==0)
    {
        s="#";
    }
    struct passwd* ptr=getpwuid(uid);
    if(ptr==NULL)
    {
        printf("mybash 1.0 $");
        fflush(stdout);
        return;
    }
    char hostname[128]={0};
    if(gethostname(hostname,128)==-1)
    {
       printf("mybash 1.0 $");
       fflush(stdout);
       return;
     }
    char curr_dir[256]={0};
    if(getcwd(curr_dir,256)==NULL)
    {
        printf("mybash 1.0 $");
        fflush(stdout);
        return;
    }
     printf("\033[1;32m%s@%s\033[0m\033[1;34m:%s\033[0m %s ",ptr->pw_name,hostname,curr_dir,s);
    fflush(stdout);
    return;
}

2.2 分割函数

2.2.1 strtok函数

char* strtok(char*str,const char*delim);

str为需要分割的字符串,delim为分割标记。

通常需要循环使用,如果需要多次分割当前字符串,在第二次使用的时候字符串那使用NULL,系统会认为继续对当前字符串进行分割(这里有个指针会指向第一次分割完后的位置)。

2.2.2分割函数实现

char* get_cmd(char buff[],char*myargv[])
{
    if(buff==NULL||myargv ==NULL)
    {
        return NULL;
    }
    int i=0;
    char*s=strtok(buff," ");
    while(s!=NULL)
    {
        myargv[i++]=s;
        s=strtok(NULL," ");
    }
    return myargv[0];
}

 2.3 命令函数

2.3.1 exit

exit表示退出当前进程。

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

2.3.2 clear

clear表示清屏,并将光标放置在最上方最左边位置

Linux Day10 ---Mybash-LMLPHP

  \033[2J   清屏  

  \033[y;xH设置光标位置 

    if(strcmp(cmd,"clear")==0)
        {
            printf("/033[2J]\033[0;0H");
        }

 2.3.3 cd

首先先说下myargv就是argv,在前面的文里说过int main(int argc,char*argv[],char*envp[]),这里的myargv里面就存储了需要切换到的路径。

其次,程序可以像用户在文件系统里那样来切换目录,就像在shell里面使用cd命令来切换目录一样。程序使用的是chdir系统调用。

int chdir(const char*path);

这里的path存储在myargv[1]里面,myargv[0]为命令cd .

成功返回0,失败返回-1

if(strcmp(cmd,"cd")==0)
        {
            if(myargv[1]!=NULL)
            {
                if(chdir(myargv[1])==-1)
                {
                    perror("cd err\n");
                }
            }
            continue;
        }

2.3.4 chmod

首先先来看看shell里面的chmod

Linux Day10 ---Mybash-LMLPHP

第一个参数为权限设置,第二个参数为需要修改的文件

所以我们通过查看书,可以发现chmod的系统调用

int chmod(const char*path,mode_t mode);

path参数指定的文件被修改为具有mode参数给出的访问权限。

注意我们这里的参数为8进制,所以涉及到参数进制转换。

 if(strcmp(cmd,"chmod")==0)
        {
            const char*path=myargv[2];
            int  mode=atoi(myargv[1]);
            int mode_1=mode/10/10;
            int mode_3=mode%10;
            int mode_2=mode/10%10;
            mode=mode_1*8*8+mode_2*8+mode_3;
            if(chmod(path,mode)<0)
            {
                printf("chmod err\n");
            }
            continue;
        }

2.3.5 pwd

getcwd在上面的打印函数中提过,详细请参考上面。

if(strcmp(cmd,"pwd")==0)
        {
            char cwd[128]={0};
            if(getcwd(cwd,128)==NULL)
            {
                printf("pwd err\n");
                continue;
            }
            printf("%s\n",cwd);
            continue;
        }

2.3.6 mkdir

mkdir系统调用用于创建目录,他相当于mkdir程序。mkdir调用将参数path作为新建目录的名字。目录的权限由参数mode设定,将含义按open系统调用的O_CREAT选项的有关定义设置。

int mkdir(const char* path,mode_t mode);

注意mode数值的设定。

 if(strcmp(cmd,"mkdir")==0)
        {
            char* path=myargv[1];
            mode_t mode=7*8*8+7*8+5;
            if(mkdir(path,mode)==-1)
            {
                printf("mkdir err\n");
            }
            continue;
        }

2.3.7 rmdir

rmdir系统调用用于删除目录,但只有在目录为空才行,rmdir程序就是用这个系统调用来完成工作的。

int rmdir(const char*path);

if(strcmp(cmd,"rmdir")==0)
        {
            char*path=myargv[1];
            DIR* dir = opendir("path");
            if(dir == NULL){
                 perror("打开目录失败");
                 exit(1);
            }
            struct dirent *ptr = NULL;
            while((ptr=readdir(dir))!=NULL);
            if(ptr == NULL){
                rmdir(myargv[1]);
            }
            continue;
        }

这里我先通过调用opendir和readdir两个函数来判断当前目录是否为空,进而使用rmdir函数来删除当前目录。

opendir函数的作用是打开一个目录并建立一个目录流,成功返回一个指向DIR结构的指针,该指针用于读取目录数据项,失败则返回一个空指针。

DIR*opendir(const char*name);

然后继续使用readdir()函数,返回一个指针,该指针指向结构里面保存着目录流dirp中下一个目录项的有关资源,后续的readdir调用返回后续的目录项,如果错误或者到达目录尾则返回NULL。

因此使用了while循环。

2.3.8 rm

rm可以直接删除普通目录文件,但是不能直接删除普通文件,需要使用到rm -r

因此这里我们需要获取到当前文件的类型

文件的类型存储在struct stat

Linux Day10 ---Mybash-LMLPHP

Linux Day10 ---Mybash-LMLPHP 

 if(strcmp(cmd,"rm")==0)
        {
            char*path1=myargv[1];
            char*path2=myargv[2];
            struct stat buf;
            char * ptr;
            int result;
            result = stat(myargv[3], &buf);
            if(S_ISREG(buf.st_mode))
            {
                if(strcmp(cmd,strcat(path1,path2))==0)
                {
                    unlink(myargv[3]);
                }
            }
            if(S_ISDIR(buf.st_mode))
            {
                rmdir(myargv[3]);
            }
        }

如果是普通文件,我们使用unlink系统调用删除一个文件。

unlink系统删除一个文件的目录项并减少他的链接数,它成功返回0失败返回-1.

如果想通过这个函数成功删除文件,你就必须拥有该文件所属目录的写和执行权限。

2.3.9 复制、更新进程

pid_t pid=fork();
        if(pid==-1)
        {
            printf("fork err\n");
            continue;
        }
        if(pid==0)
        {
            execvp(cmd,myargv);
            printf("exec err\n");
            exit(0);
        }
        wait(NULL);

剩余命令我们后续更新。。。。敬请期待

接下来我们看一下效果

三、使用看效果

Linux Day10 ---Mybash-LMLPHP

Linux Day10 ---Mybash-LMLPHP 

Linux Day10 ---Mybash-LMLPHP 下次我们更新touch ,mv,cp,ls,cat等命令

 

08-24 23:27