《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目录下查找命令的可执行程序。

函数源码

准备代码

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

#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函数不会看不懂

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);
}

print_prompt函数

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

void print_prompt(){
    printf("myshell$$ ");
}

get_input函数

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函数

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函数

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

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");
}

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

首先是这段代码

//查看命令里是否有重定向符号
    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,然后报命令格式错误。

然后是这里

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命令,所以会用到子进程来操作(实际上整个命令的处理都是要用子进程),那么就要单独把管道符后面的命令先存起来了

最后是这么一长串

    //创建子进程
    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就指定了程序的标准输入输出重定向

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

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博客

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

#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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/288244.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Dora-rs 机器人框架学习教程(1)—— Dora-rs安装

1、dora简介 Dora-rs[1] 是一个基于 Rust 实现的化机器人框架&#xff0c;其具有极高的实时性能。Dora-rs使用Rust语言做数据流的传输和调度管理&#xff0c;可以大大减少了数据的重复拷贝和传输。它提供了Rust语言和Python语言之间的无缝集成&#xff0c;减少了跨语言的性能代…

C++上位软件通过LibModbus开源库和西门子S7-1200/S7-1500/S7-200 PLC进行ModbusTcp 和ModbusRTU 通信

前言 一直以来上位软件比如C等和西门子等其他品牌PLC之间的数据交换都是大家比较头疼的问题&#xff0c;尤其是C上位软件程序员。传统的方法一般有OPC、Socket 等&#xff0c;直到LibModbus 开源库出现后这种途径对程序袁来说又有了新的选择。 Modbus简介 Modbus特点 1 &#…

高压继电器,未来几年市场将保持稳定增长

高压继电器是一种用于控制大功率电气设备的开关装置&#xff0c;广泛应用于电力系统、轨道交通、工业自动化等领域。随着各行业对电气控制需求的不断增加&#xff0c;高压继电器市场也在不断扩大。全球高压继电器市场分析&#xff1a; 在全球市场中&#xff0c;目前主要的高压继…

拒绝纸张浪费,Paperless-ngx开源文档管理系统将纸质版转换成可搜索的电子版档案

GitHub&#xff1a;GitHub - paperless-ngx/paperless-ngx: A community-supported supercharged version of paperless: scan, index and archive all your physical documents 在线演示&#xff1a;https://demo.paperless-ngx.com 官网&#xff1a;https://docs.paperless-n…

【力扣100】46.全排列

添加链接描述 class Solution:def permute(self, nums: List[int]) -> List[List[int]]:# 思路是使用回溯if not nums:return []def dfs(path,depth,visited,res):# 出递归的条件是当当前的深度已经和nums的长度一样了&#xff0c;把path加入数组&#xff0c;然后出递归if …

手机流量卡推广分销网站php源码,多功能的号卡推广分销管理系统

源码简介 拥有多个接口&#xff0c;包括运营商接口&#xff0c;并支持无限三级代理。 最简单易用的PHP系统&#xff0c;它自带自动安装向导&#xff0c;可以让你轻松安装和部署。 该系统集成了多个第三方接口资源&#xff0c;能够满足你的不同需求。采用全系统双色主题&…

Python 自学(二) 之流程控制语句

目录 1. if ... elif ... else 语句 P62 2. True False 3. for 数值循环 in range() P69 4. for 遍历字符串&#xff0c;列表&#xff0c;元组&#xff0c;集合和字典 in obj P70 5. pass 空语句 1. if ... elif ... else 语句 P62 每个判断语句后面要加 :elif …

机器学习中的监督学习基本算法-逻辑回归简单介绍

逻辑回归 逻辑回归&#xff08;Logistic Regression&#xff09;是一种用于解决二分类问题的统计学习方法&#xff0c;尽管名字中带有"回归"一词&#xff0c;但实际上它是一种分类算法。逻辑回归的主要目标是通过学习从输入特征到一个离散的输出&#xff08;通常是0…

log4cplus visual c++ 编译及调试小记

简介 最近在调试一款SATA加密设备&#xff0c;发现设备有时加密出来的数据&#xff0c;再解密时与明文对不上&#xff0c;怀疑是通信问题。因此&#xff0c;急需要在测试工具中加入通信日志。由于对第三方日志库都不熟悉&#xff0c;所以随便选了个log4cplus软件集成到现有工具…

以STM32为例,实现按键的短按和长按

以STM32为例&#xff0c;实现按键的短按和长按 目录 以STM32为例&#xff0c;实现按键的短按和长按1 实现原理2 实现代码3 测试结束语 1 实现原理 简单来说就是通过设置一个定时器来定时扫描几个按键的状态&#xff0c;并分别记录按键按下的持续时间&#xff0c;通过时间的长短…

百度百科词条创建多久可以通过?

一个优质的百度百科词条&#xff0c;能提升个人或企业的品牌形象。因此&#xff0c;越来越多的人希望创建自己的百度百科词条&#xff0c;那么&#xff0c;创建一个百度百科词条到底需要多久才能通过审核呢&#xff1f;接下来伯乐网络传媒就来给大家分享一下。 一、百度百科词条…

【Qt之Quick模块】7. Quick基础、常用组件Item、Rectangle、Text、TextInput、TextEdit等

1. 概述 Qt Quick模块是编写QML应用程序的标准库。Qt QML模块提供QML引擎和语言基础结构&#xff0c;Qt Quick模块提供用QML创建用户界面所需的所有基本类型。它提供了一个可视化画布&#xff0c;包括用于创建和动画化可视化组件、接收用户输入、创建数据模型和视图以及延迟对…

静态网页设计——海贼王

前言 使用前端经典三件套HTMLCSSJS实现的海贼王静态网页课程设计&#xff0c;适合我们的童年&#xff01; 主要内容 首页 首页最上方有一个轮播图&#xff0c;可以自动切换图片&#xff0c;使用js实现。 轮播图往下&#xff0c;就是列出一些比较经典的海贼王影片&#xf…

2023年度最热 AI 应用 TOP 50,除了 ChatGPT 还有这么多宝藏

原文章链接&#xff1a;年度最热 AI 应用 TOP 50&#xff0c;除了 ChatGPT 还有这么多宝藏 - IT之家 更多消息&#xff1a;AI人工智能行业动态&#xff0c;aigc应用领域资讯 在 AI 工具激烈竞争的一年中&#xff0c;尽管ChatGPT在访问量上遥遥领先&#xff0c;但单次使用时长未…

Python之字符编码汇总

一、常见编码 ASCII&#xff1a;ASCII码即美国标准信息交换码(American Standard Code for Information Interchange)。由于计算机内部所有信息最终都是一个二进制值&#xff0c;而每一个二进制位&#xff08;bit&#xff09;有0和1两种状态&#xff0c;因此八个二进制位就可以…

gookit/color - Go语言命令行色彩使用库教程

gookit/color - Go语言命令行色彩使用库教程 1.安装2.基础颜色(16-color)3.256色彩/RGB风格 1.安装 go get github.com/gookit/color2.基础颜色(16-color) 提供通用的API方法&#xff1a;Print Printf Println Sprint Sprintf 1、例如&#xff1a; color.Yellow.Println(&q…

centos7 ping不通域名

如果ip能ping通&#xff0c;ping不通域名可以试试以下操作&#xff1a; 1.编辑resolv.conf文件 vi /etc/resolv.conf 添加 nameserver 8.8.8.8 2.编辑nsswitch.conf vi /etc/nsswitch.conf 改成下图所示&#xff1a; 3.编辑sysctl.conf vi /etc/sysctl.conf 加上两行内…

macOS跨进程通信: FIFO(有名管道) 创建实例

一&#xff1a; 简介 在类linux系统中管道分为有名管道和匿名管道。两者都能单方向的跨进程通信。 匿名管道&#xff08;pipe&#xff09;: 必须是父子进程之间&#xff0c;而且子进程只能由父进程fork() 出来的&#xff0c;才能继承父进程的管道句柄&#xff0c;一般mac 开发…

1分钟生成爆款风景视频,Stable Video Diffusion最简教程

AI视频是2024年的重头戏&#xff0c;各大AI厂商都在跑视频技术&#xff0c;快速推出更牛的黑科技&#xff0c;SD其实在11月底就出了一款官方视频大模型-SVD&#xff0c;来跟runway、pika抢这块大蛋糕。 之前生成的视频效果还不是很理想&#xff0c;远没runway效果好&#xff0c…

【Mybatis】深入学习MyBatis:高级特性与Spring整合

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; Mybatis ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 高级特性 1 一级缓存和二级缓存 一级缓存 二级缓存 2 延迟加载 5 整合Spring 1 MyBatis-Spring模块 2 事务管理 结…