《Linux C编程实战》笔记:实现自己的myshell

ok,考完试成功复活

这次是自己的shell命令程序的示例

流程图:

关键函数

1.void print_prompt()

函数说明:这个函数打印myshell提示符,即"myshell$$".

2.void get_input(char *buf)

函数说明:获得一条指令,buf用来存放输入的命令。命令过长会终止程序;以换行符\n作为结束

3.void explain_input(char *buf,int *argcount,char arglist[100][256])

函数说明:解析buf中存放的命令,把选项放在arglist中,同时把argcount的值改成选项的个数。比如"ls -l /tmp",则arglist[0],arglist[1].arglist[2]分别是"ls","-l","/tmp"。

4.do_cmd(int argcount,char arglist[100][256])

函数说明:执行命令

5.int find_command(char *command)

函数说明:功能是分别在当前目录,/bin目录,/usr/bin目录下查找命令的可执行程序。

函数源码

准备代码

首先是一些头文件和定义的代码

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<dirent.h>
//头文件里都是以前出现过的,我就不再说每个的用处了
#define normal 0 //一般的命令
#define out_redirect 1 //输出重定向
#define in_redirect 2 //输入重定向
#define have_pipe 3 //命令中有管道
void print_prompt();//打印提示符
void get_input(char *);//得到输入的命令
void explain_input(char *,int *,char [][256]);//对输入的命令进行解析
void do_cmd(int,char [][256]);//执行命令
int find_command(char *);//查找命令中的可执行程序

main函数

因为这个程序模块化的很清楚,直接看main函数不会看不懂

cpp 复制代码
int main(int argc,char **argv){
    int i;
    int argcount=0;//这个是存选项数的
    char arglist[100][256];//这个是存选项的
    char **arg=nullptr;
    char *buf=nullptr;//这个是得到输入的数组
    //buf=new char[256];
    buf=(char *)malloc(256);//用C的malloc声明
    if(buf==nullptr){
        perror("malloc failed");//perror也出现过好多次了,详见我以前写的内容
        exit(-1);
    }
    while (1)//循环读入命令
    {
        memset(buf,0,256);//先把buf清空
        print_prompt();//打印提示符
        get_input(buf);//读入命令
        //如果是exit或logout就退出
        if(strcmp(buf,"exit\n")==0||strcmp(buf,"logout\n")==0)
            break;
        for(i=0;i<100;i++)//把arglist清空
            arglist[i][0]='\0';
        argcount=0;
        explain_input(buf,&argcount,arglist);//通过这个函数去解释buf里面的命令,函数会更新argcount和arglist
        do_cmd(argcount,arglist);//执行命令
    }
    if(buf!=nullptr){//退出后记得清空内存
        free(buf);
        buf=nullptr;
    }
    exit(0);
}

最简单的一集,打印提示符就完了

cpp 复制代码
void print_prompt(){
    printf("myshell$$ ");
}

get_input函数

cpp 复制代码
void get_input(char *buf){
    int len=0;
    char ch;
    //古法读入字符串,长度最长是256,遇到换行停止
    ch=getchar();
    while (len<256&&ch!='\n')
    {
        buf[len++]=ch;
        ch=getchar();
    }
    if(len==256){
        printf("command is too long \n");
        exit(-1);
    }
    buf[len]='\n';
    len++;
    buf[len]='\0';//记得最后添个'\0'
}

explain_input函数

cpp 复制代码
void explain_input(char *buf,int *argcount,char arglist[][256]){
    //解释后的结果会存到arglist里
    //具体解释的方式就是根据空格分割,分割后的每个字符串存到arglist里
    //也就C语言没有split函数,不然至于这么麻烦吗...
    char *p=buf;
    char *q=buf;
    int number=0;
    while (1)
    {
        if(p[0]=='\n') break;
        if(p[0]==' ') p++;
        //首先跳过空格走到一个字符串的开头
        else{
            q=p;//然后指针q指向这个字符串的开头,用q来遍历字符串直到下一个空格或者换行(换行代表结束)
            number=0;
            while (q[0]!=' '&&q[0]!='\n')
            {
                number++;//顺便记录字符串的长度(其实不用number也行,q-p不就得了,书上反正用了number)
                q++;
            }
            //循环后现在p是字符串的开头,q是字符串结尾的下一个空格位置
            strncpy(arglist[*argcount],p,number+1);//把分割的字符串赋值给arglist
            arglist[*argcount][number]='\0';//C风格的字符串记得结尾加'\0'
            (*argcount)++;选项数加一
            p=q;//p直接跳到q的位置继续循环
        }
    }
}

do_cmd函数

这个函数才是关键好吧,执行输入的指令

cpp 复制代码
void do_cmd(int argcount,char arglist[][256]){
    int flag=0;//重定向的标志
    int how=0;//具体是什么重定向,取值是define的那些值
    int background=0;//标志是否有后台运行符 &
    int status;//这是给waitpid用的
    int i;
    int fd;//这是文件描述符
    char *arg[argcount+1];
    char *argnext[argcount+1];//这是给管道用的
    char *file;//文件名
    pid_t pid;//进程号
    for(i=0;i<argcount;i++){
        arg[i]=(char *)arglist[i];//首先先把arglist的值复制到arg里面(其实我也不是很明白为什么要重开一个数组)
    }
    arg[argcount]=nullptr;//数组多开的那个放空指针

    //查看命令是否有后台运行符
    for(i=0;i<argcount;i++){
        if(strncmp(arg[i],"&",1)==0){
            //看一下最开始的函数描述,这个示例代码的后台运行符&只能出现在最后
            if(i==argcount-1){
                background=1;
                arg[argcount-1]=nullptr;
                break;
            }
            else{//所以如果不是出现在最后就提示命令错误
                printf("wrong command\n");
                return;
            }
        }
    }

    for(i=0;arg[i]!=nullptr;i++){
        if(strcmp(arg[i],">")==0){
            flag++;
            how=out_redirect;
            if(arg[i+1]==nullptr)
                flag++;
        }
        if(strcmp(arg[i],"<")==0){
            flag++;
            how=in_redirect;
            if(i==0)
                flag++;
        }
        if(strcmp(arg[i],"|")==0){
            flag++;
            how=have_pipe;
            if(arg[i+1]==nullptr)
                flag++;
            if(i==0)
                flag++;
        }
    }
    if(flag>1){
        printf("wrong command\n");
        return;
    }
    if(how==out_redirect){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],">")==0){
                file=arg[i+1];
                arg[i]=nullptr;
            }
        }
    }
    if(how==in_redirect){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],"<")==0){
                file=arg[i+1];
                arg[i]=nullptr;
            }
        }
    }
    if(how==have_pipe){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],"|")==0){
                arg[i]=nullptr;
                int j;
                for(j=i+1;arg[j]!=nullptr;j++)
                    argnext[j-i-1]=arg[j];
                argnext[j-i-1]=arg[j];
                break;
            }
        }
    }
    if((pid=fork())<0){
        printf("fork error\n");
        return;
    }
    switch (how)
    {
    case 0:
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 1:
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd=open(file,O_RDWR|O_CREAT|O_TRUNC,0644);
            dup2(fd,1);
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 2:
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd=open(file,O_RDONLY);
            dup2(fd,0);
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 3:
        if(pid==0){
            pid_t pid2;
            int status2;
            int fd2;
            if((pid2=fork())<0){
                printf("fork2 error\n");
                return;
            }
            else if(pid2==0){
                if(!(find_command(arg[0]))){
                    printf("%s:command not fount\n",arg[0]);
                    exit(0);
                }
                fd2=open("/tmp/youdonotknowfile",O_WRONLY|O_CREAT|O_TRUNC,0644);
                dup2(fd2,1);
                execvp(arg[0],arg);
                exit(0);
            }
            if(waitpid(pid2,&status2,0)==-1)
                printf("wait for child process error\n");
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd2=open("/tmp/youdonotknowfile",O_RDONLY);
            dup2(fd,0);
            execvp(argnext[0],argnext);
            if(remove("/tmp/youdonotknowfile"))
                printf("remove error");
            exit(0);
        }
        break;
    default:
        break;
    }
    if(background==1){
        printf("[process id %d]\n",pid);
        return;
    }
    if(waitpid(pid,&status,0)==-1)
        printf("wait for child process eerror\n");
}

代码里没有注释的地方是在这里具体说明,单靠注释应该还是很难说清的

首先是这段代码

cpp 复制代码
//查看命令里是否有重定向符号
    for(i=0;arg[i]!=nullptr;i++){
        if(strcmp(arg[i],">")==0){
            flag++;
            how=out_redirect;
            if(arg[i+1]==nullptr)
                flag++;
        }
        if(strcmp(arg[i],"<")==0){
            flag++;
            how=in_redirect;
            if(i==0)
                flag++;
        }
        if(strcmp(arg[i],"|")==0){
            flag++;
            how=have_pipe;
            if(arg[i+1]==nullptr)
                flag++;
            if(i==0)
                flag++;
        }
    }
    if(flag>1){
        printf("wrong command\n");
        return;
    }

首先要说明,本程序只能支持处理一个重定向符,所以既有输入重定向又有输出重定向是错误的,这是最底下flag>1的一个意思,即重定向符太多了。

但是代码里还有其他地方也有flag++的操作,这是为什么?

这需要一点点linux重定向的知识。你光写个>是没用的,肯定是要加文件 比如这样的命令:

echo "hello" > test.txt

所以像 '>'后面就不能是空了

还有像管道符,它肯定不能是命令的第一个。

不过这个示例代码里,我怀疑它是故意的,>也不能是第一个吧,<后面我也不知道可以不跟文件名的命令,所以最好是把管道那段的判断替换<和>。

所以如果出现这种错误,flag就会超过1,然后报命令格式错误。

然后是这里

cpp 复制代码
if(how==out_redirect){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],">")==0){
                file=arg[i+1];//得到文件名
                arg[i]=nullptr;
            }
        }
    }
    if(how==in_redirect){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],"<")==0){
                file=arg[i+1];//得到文件名
                arg[i]=nullptr;
            }
        }
    }
    if(how==have_pipe){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],"|")==0){
                arg[i]=nullptr;
                int j;
                for(j=i+1;arg[j]!=nullptr;j++)//把管道符后面的全都存到argnext里来
                    argnext[j-i-1]=arg[j];
                argnext[j-i-1]=arg[j];
                break;
            }
        }
    }

这段还是能理解的,主要是获得文件名,文件名 自然是跟在重定向符后面了。(你看这里的<后面就跟文件名了,所以我说上面有问题)

这里设置arg[i]=nullptr我估计是为了减少遍历吧,示例代码里for循环的终止条件都是arg[i]!=nullptr 处理完这部分在此处设为nullptr,这样后面遍历就不用遍历到这里了、

对于管道,像一般的管道命令:echo "Hello, World!" | grep "Hello"

实际上相当于两个shell命令,所以会用到子进程来操作(实际上整个命令的处理都是要用子进程),那么就要单独把管道符后面的命令先存起来了

最后是这么一长串

cpp 复制代码
    //创建子进程
    if((pid=fork())<0){
        printf("fork error\n");
        return;
    }
    switch (how)//根据how来进行不同的处理
    {
    case 0://命令符中不含重定向和管道
        if(pid==0){//pid=0是子进程
            if(!(find_command(arg[0]))){//看这个命令是不是系统有的
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            execvp(arg[0],arg);//***
            exit(0);
        }
        break;
    case 1://有输出重定向
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd=open(file,O_RDWR|O_CREAT|O_TRUNC,0644);//向文件里写
            dup2(fd,1);
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 2://有输入重定向
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd=open(file,O_RDONLY);//只需要从文件里读,所以只用O_RDONLY
            dup2(fd,0);
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 3://有管道
        if(pid==0){
            pid_t pid2;
            int status2;
            int fd2;
            //再创建一个子进程
            if((pid2=fork())<0){
                printf("fork2 error\n");
                return;
            }
            else if(pid2==0){
                //这是管道的子进程了
                if(!(find_command(arg[0]))){
                    printf("%s:command not fount\n",arg[0]);
                    exit(0);
                }
                fd2=open("/tmp/youdonotknowfile",O_WRONLY|O_CREAT|O_TRUNC,0644);
                dup2(fd2,1);
                execvp(arg[0],arg);
                exit(0);
            }
            if(waitpid(pid2,&status2,0)==-1)
                printf("wait for child process error\n");
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd2=open("/tmp/youdonotknowfile",O_RDONLY);
            dup2(fd,0);
            execvp(argnext[0],argnext);
            if(remove("/tmp/youdonotknowfile"))
                printf("remove error");
            exit(0);
        }
        break;
    default:
        break;
    }
    if(background==1){
        printf("[process id %d]\n",pid);
        return;
    }
    if(waitpid(pid,&status,0)==-1)
        printf("wait for child process error\n");
}

最主要的代码无疑是execvp(arg[0],arg);这是什么意思呢?

其实在《Linux C编程实战》笔记:进程操作之退出,执行,等待-CSDN博客 出现过,不过还是稍微解释一下

execvp是让子进程执行另一个程序,那这个程序是啥?就是我们给出的参数arg[0]所指定的可执行文件,比如说

char *args[] = {"ls", "-l", NULL}; execvp("ls", args);

那子进程就会执行ls命令。

那arg[0]其实就是我们的指令了,arg也是我们指令的具体参数,所以子进程会帮我们执行指令。

还要再解释一下,execvp会先在当前路径下找有没有名为arg[0]的可执行文件,没有的话会在环境变量下找,而默认的环境变量是包含/bin的,所以为什么我们要先find_command。而像shell命令都是已经存好了的,无需我们再写一个。这样执行execvp会到/bin下执行一般的shell命令。

dup2函数在《Linux C编程实战》笔记:一些系统调用-CSDN博客有讲解,不知道的可以去看看

当然如果连open调用也不知道的话可以看这里《Linux C编程实战》笔记:文件读写-CSDN博客

有个疑问是怎么就实现了输入输出的重定向?

dup2(fd, 0): 这一行代码将文件描述符 fd 复制到标准输入文件描述符 0 上。这意味着标准输入现在被重新定向到你打开的文件 file

答案就在这个dup2里,0是默认的标准输入文件描述符,自然1是标准输出文件描述符。我们的fd已经打开了指定的文件,然后通过dup2就指定了程序的标准输入输出重定向

如果你想将程序的输出重定向到一个文件,你可以使用类似如下的代码:

cpp 复制代码
int fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1) {
    perror("open");
    exit(EXIT_FAILURE);
}

// 将标准输出重定向到文件描述符 fd
dup2(fd, 1);

// 执行输出操作,结果将写入 output.txt 文件
printf("This will be written to output.txt\n");

// 关闭文件描述符 fd
close(fd);

虽然execvp更改了子进程执行的程序,但是标准输入输出是保持的,这也是为什么在输入重定向的例子中,通过 dup2 将文件描述符复制到标准输入后,execvp 执行的新程序将从这个文件描述符读取输入

至于管道那部分,实际上就是创建了一个子进程,让子进程先执行管道符|前面部分的命令,同时使用输出重定向把结果放到一个临时文件里,等子进程结束再在父进程执行|后面的命令,同时使用输入重定向从那个临时文件里读取之前运行的结果。最后把临时文件删除了。

至于waitpid这个函数,直接看《Linux C编程实战》笔记:进程操作之退出,执行,等待-CSDN博客有讲,内容太多我就不复述了。

find_command函数

主要就是目录的遍历

目录遍历不会的看这里《Linux C编程实战》笔记:目录操作-CSDN博客

cpp 复制代码
int find_command(char *command){
    DIR *dp;
    struct dirent *dirp;
    const char *path[]={"./","/bin","/usr/bin",nullptr};//从这几个目录里找
    //这个意思是像 ./a.out这种命令,就不用看./了,所以加了2
    if(strncmp(command,"./",2)==0)
        command=command+2;
    int i=0;
    while (path[i]!=nullptr)
    {
        if((dp=opendir(path[i]))==nullptr)
            printf("can not open /bin \n");
        while ((dirp=readdir(dp))!=nullptr)
        {
            if(strcmp(dirp->d_name,command)==0){//找到了
                closedir(dp);
                return 1;
            }
        }
        closedir(dp);
        i++;
    }
    return 0;//没找到
}

最后打了半天的代码,也是幸好能成功运行

源码copy

最后把所有代码一整个都放在这,不过是没有注释的,方便大家直接copy

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<dirent.h>
#define normal 0
#define out_redirect 1
#define in_redirect 2
#define have_pipe 3
void print_prompt();
void get_input(char *);
void explain_input(char *,int *,char [][256]);
void do_cmd(int,char [][256]);
int find_command(char *);
int main(int argc,char **argv){
    int i;
    int argcount=0;
    char arglist[100][256];
    char **arg=nullptr;
    char *buf=nullptr;
    //buf=new char[256];
    buf=(char *)malloc(256);
    if(buf==nullptr){
        perror("malloc failed");
        exit(-1);
    }
    while (1)
    {
        memset(buf,0,256);
        print_prompt();
        get_input(buf);
        if(strcmp(buf,"exit\n")==0||strcmp(buf,"logout\n")==0)
            break;
        for(i=0;i<100;i++)
            arglist[i][0]='\0';
        argcount=0;
        explain_input(buf,&argcount,arglist);
        do_cmd(argcount,arglist);
    }
    if(buf!=nullptr){
        free(buf);
        buf=nullptr;
    }
    exit(0);
}
void print_prompt(){
    printf("myshell$$ ");
}
void get_input(char *buf){
    int len=0;
    char ch;
    ch=getchar();
    while (len<256&&ch!='\n')
    {
        buf[len++]=ch;
        ch=getchar();
    }
    if(len==256){
        printf("command is too long \n");
        exit(-1);
    }
    buf[len]='\n';
    len++;
    buf[len]='\0';
}

void explain_input(char *buf,int *argcount,char arglist[][256]){
    char *p=buf;
    char *q=buf;
    int number=0;
    while (1)
    {
        if(p[0]=='\n') break;
        if(p[0]==' ') p++;
        else{
            q=p;
            number=0;
            while (q[0]!=' '&&q[0]!='\n')
            {
                number++;
                q++;
            }
            strncpy(arglist[*argcount],p,number+1);
            arglist[*argcount][number]='\0';
            (*argcount)++;
            p=q;
        }
    }
}
void do_cmd(int argcount,char arglist[][256]){
    int flag=0;
    int how=0;
    int background=0;
    int status;
    int i;
    int fd;
    char *arg[argcount+1];
    char *argnext[argcount+1];
    char *file;
    pid_t pid;
    for(i=0;i<argcount;i++){
        arg[i]=(char *)arglist[i];
    }
    arg[argcount]=nullptr;
    for(i=0;i<argcount;i++){
        if(strncmp(arg[i],"&",1)==0){
            if(i==argcount-1){
                background=1;
                arg[argcount-1]=nullptr;
                break;
            }
            else{
                printf("wrong command\n");
                return;
            }
        }
    }
    for(i=0;arg[i]!=nullptr;i++){
        if(strcmp(arg[i],">")==0){
            flag++;
            how=out_redirect;
            if(arg[i+1]==nullptr)
                flag++;
        }
        if(strcmp(arg[i],"<")==0){
            flag++;
            how=in_redirect;
            if(i==0)
                flag++;
        }
        if(strcmp(arg[i],"|")==0){
            flag++;
            how=have_pipe;
            if(arg[i+1]==nullptr)
                flag++;
            if(i==0)
                flag++;
        }
    }
    if(flag>1){
        printf("wrong command\n");
        return;
    }
    if(how==out_redirect){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],">")==0){
                file=arg[i+1];
                arg[i]=nullptr;
            }
        }
    }
    if(how==in_redirect){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],"<")==0){
                file=arg[i+1];
                arg[i]=nullptr;
            }
        }
    }
    if(how==have_pipe){
        for(i=0;arg[i]!=nullptr;i++){
            if(strcmp(arg[i],"|")==0){
                arg[i]=nullptr;
                int j;
                for(j=i+1;arg[j]!=nullptr;j++)
                    argnext[j-i-1]=arg[j];
                argnext[j-i-1]=arg[j];
                break;
            }
        }
    }
    if((pid=fork())<0){
        printf("fork error\n");
        return;
    }
    switch (how)
    {
    case 0:
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 1:
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd=open(file,O_RDWR|O_CREAT|O_TRUNC,0644);
            dup2(fd,1);
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 2:
        if(pid==0){
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd=open(file,O_RDONLY);
            dup2(fd,0);
            execvp(arg[0],arg);
            exit(0);
        }
        break;
    case 3:
        if(pid==0){
            pid_t pid2;
            int status2;
            int fd2;
            if((pid2=fork())<0){
                printf("fork2 error\n");
                return;
            }
            else if(pid2==0){
                if(!(find_command(arg[0]))){
                    printf("%s:command not fount\n",arg[0]);
                    exit(0);
                }
                fd2=open("/tmp/youdonotknowfile",O_WRONLY|O_CREAT|O_TRUNC,0644);
                dup2(fd2,1);
                execvp(arg[0],arg);
                exit(0);
            }
            if(waitpid(pid2,&status2,0)==-1)
                printf("wait for child process error\n");
            if(!(find_command(arg[0]))){
                printf("%s:command not fount\n",arg[0]);
                exit(0);
            }
            fd2=open("/tmp/youdonotknowfile",O_RDONLY);
            dup2(fd,0);
            execvp(argnext[0],argnext);
            if(remove("/tmp/youdonotknowfile"))
                printf("remove error");
            exit(0);
        }
        break;
    default:
        break;
    }
    if(background==1){
        printf("[process id %d]\n",pid);
        return;
    }
    if(waitpid(pid,&status,0)==-1)
        printf("wait for child process error\n");
}
int find_command(char *command){
    DIR *dp;
    struct dirent *dirp;
    const char *path[]={"./","/bin","/usr/bin",nullptr};
    if(strncmp(command,"./",2)==0)
        command=command+2;
    int i=0;
    while (path[i]!=nullptr)
    {
        if((dp=opendir(path[i]))==nullptr)
            printf("can not open /bin \n");
        while ((dirp=readdir(dp))!=nullptr)
        {
            if(strcmp(dirp->d_name,command)==0){
                closedir(dp);
                return 1;
            }
        }
        closedir(dp);
        i++;
    }
    return 0;
}
相关推荐
知星小度S8 分钟前
系统核心解析:深入文件系统底层机制——Ext系列探秘:从磁盘结构到挂载链接的全链路解析
linux
Rousson11 分钟前
硬件学习笔记--93 静电防护方案(电阻、磁珠、电感、TVS等)
笔记·单片机·学习
2401_8904430213 分钟前
Linux 基础IO
linux·c语言
思成不止于此21 分钟前
【MySQL 零基础入门】事务精讲(二):ACID 特性与并发问题
数据库·笔记·学习·mysql
happyhappy没有句号1 小时前
嵌入式单片机一套通关学习笔记
笔记·单片机·嵌入式硬件·学习
悠哉悠哉愿意1 小时前
【嵌入式学习笔记】工程模板建立
笔记·嵌入式硬件·学习
智慧地球(AI·Earth)1 小时前
在Linux上使用Claude Code 并使用本地VS Code SSH远程访问的完整指南
linux·ssh·ai编程
d111111111d1 小时前
STM32外设基地址与寄存器偏移地址的深度解析
笔记·stm32·单片机·嵌入式硬件·学习
老王熬夜敲代码2 小时前
解决IP不够用的问题
linux·网络·笔记
polarislove02142 小时前
8.1 时钟树-嵌入式铁头山羊STM32笔记
笔记·stm32·嵌入式硬件