Linux命令myshell的自我实现

简介: Linux命令myshell的自我实现

打造一个绝无伦比的 xxx-super-shell (xxx 是你的名字),它能实现下面这些功能:

  • 实现 管道 (也就是 |)
  • 实现 输入输出重定向(也就是 < > >>)
  • 实现 后台运行(也就是 & )
  • 实现 cd,要求支持能切换到绝对路径,相对路径和支持 cd -
  • 屏蔽一些信号(如 ctrl + c 不能终止)
  • 界面美观
  • 开发过程记录、总结、发布在个人博客中

要求:

不得出现内存泄漏,内存越界等错误
学会如何使用 gdb 进行调试,使用 valgrind 等工具进行检测

Example

xxx@xxx ~ $ ./xxx-super-shell
xxx@xxx ~ $ echo ABCDEF
xxx@xxx ~ $ echo ABCDEF > ./1.txt
xxx@xxx ~ $ cat 1.txt
xxx@xxx ~ $ ls -t >> 1.txt
xxx@xxx ~ $ ls -a -l | grep abc | wc -l > 2.txt
xxx@xxx ~ $ python < ./1.py | wc -c
xxx@xxx ~ $ mkdir test_dir
xxx@xxx ~/test_dir $ cd test_dir
xxx@xxx ~ $ cd -
xxx@xxx ~/test_dir $ cd -
xxx@xxx ~ $ ./xxx-super-shell # shell 中嵌套 shell
xxx@xxx ~ $ exit
xxx@xxx ~ $ exit

知识要点

  • 懂得如何使用 shell
  • 理解 shell 原理
  • Linux系统编程:进程控制
  • gdb
  • algrind

参考资料

  • man 手册.
  • MichaelKerrisk.Linux/UNIX系统编程手册[M].北京:人民邮电出版社.
  • W.RichardStevens.Stephen.UNIX环境高级编程[M].第3版.戚正伟,译.北京:人民邮电出版社.

代码实现

代码框架

打印提示符

void printname()
{
    
  char *name1 = "gty@gty-Lenovo-Legion";
  printf("\033[1m\033[32m%s\033[0m", name1);
  printf(":");
  getcwd(arr,sizeof(arr));
  printf("\033[1m\033[34m%s\033[0m", arr);
  printf("$ ");
  fflush(stdout); //清空缓冲区,默认为行缓冲,提示符不是以\n结尾的
}

参数输入

int main()
{
    
  read_history(NULL);
  signal(SIGINT, SIG_IGN);
  signal(SIGHUP, SIG_IGN);
  // char commod[MAX];
  while (1)
  {
    
    char *argv[MAX] = {
    NULL};
    //打印提示符
    printname();
    // commod[0]=0;
    // fgets(commod,MAX,stdin);
    //fflush(stdout);
    char *commod = readline(" ");
    if (commod == NULL) //屏蔽掉ctrl d 出现死循环的情况
    {
    
      printf("\n");
      continue;
    }
    add_history(commod);
    write_history(NULL);
    // commod[strlen(commod)-1]=0;
    if (strlen(commod) == 0) //屏蔽掉ctrl d 出现死循环的情况
    {
    
      // printf("\n");
      continue;
    }

    const char *mark = " "; //分割标识符,用strtok函数以空格为分割标识对字符串commod进行分割,将每个指令取出来.
    int i = 1;
    argv[0] = strtok(commod, mark);
    while (argv[i] = strtok(NULL, mark))
    {
    
      i++;
    }
    // free(commod);
    commodAnalsy(argv, i);//解析参数的函数
     free(commod);
  }
}

解析参数

int isdo(char *argv[], int count)
{
    
  int flag = 10, i;
  if (argv[0] == NULL)
    return 0;
  if (strcmp(argv[0], "cd") == 0)
  {
    
    flag = 1;
  }
  for (i = 0; i < count; i++)
  {
    
    if (strcmp(argv[i], ">") == 0)
      flag = 2;
    if (strcmp(argv[i], "|") == 0)
      flag = 3;
    if (strcmp(argv[i], ">>") == 0)
      flag = 4;
    if (strcmp(argv[i], "<") == 0)
      flag = 5;
    if (strcmp(argv[i], "<<") == 0)
      flag = 6;
    if (strcmp(argv[i], "&") == 0)
    {
    
        pass = 1;
        argv[i]=NULL;
    }
  }
  return flag;
}
void commodAnalsy(char *argv[], int number)
{
    
  int flag = isdo(argv, number);
  if(pass==1)
  {
    
    number--;
  }
  if (flag == 1)
  {
    
    mycd(argv);
  }
  else if (strcmp(argv[0], "history") == 0)
  {
    
    ShowHistory();
  }
  else if (strcmp(argv[0], "exit") == 0)
  {
    
    printf("exit\n");
    printf("有停止的任务\n");
    exit(0);
  }
  else if (flag == 2) //输出重定向'>'
  {
    
    mydup(argv);
  }
  else if (flag == 3) //管道'|'
  {
    
    callCommandWithPipe(argv, number);
  }
  else if (flag == 4) //输出重定向'>>'
  {
    
    mydup2(argv);
  }
  else if (flag == 5)//输入重定向'<'
  {
    
    mydup3(argv);
  }
  else if (flag == 10) //需要子进程进行执行的第三方函数
  {
    
    if (strcmp(argv[0], "ll") == 0)
    {
    
      strcpy(argv[0], "ls");
      argv[number++] = "-l";
    }
    if (strcmp(argv[0], "ls") == 0)
      argv[number++] = "--color=auto";
    pid_t pid = fork();
    if (pid < 0)
    {
    
      perror("fork");
      exit(1);
    }
    else if (pid == 0) //子进程
    {
    
      execvp(argv[0], argv); //执行命令
      perror("commod");
      exit(1);
    }
    else if (pid > 0) //父进程
    {
    
      if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
      waitpid(pid, NULL, 0);
    }
  }
}

cd指令

char strpwd[MAX]; //用来存放上一次的路劲  实现 cd -
void mycd(char *argv[])
{
    
  if (argv[1] == NULL)
  {
    
    getcwd(strpwd, sizeof(strpwd));
    chdir("/home");
  }
  else if (strcmp(argv[1], "-") == 0)
  {
    
    char strpwd1[MAX];
    getcwd(strpwd1, sizeof(strpwd));
    chdir(strpwd);
    printf("%s\n", strpwd);
    strcpy(strpwd, strpwd1);
  }
  else if (strcmp(argv[1], "~") == 0)
  {
    
    getcwd(strpwd, sizeof(strpwd));
    chdir("/home/gty");
  }
  else
  {
    
    getcwd(strpwd, sizeof(strpwd));
    chdir(argv[1]);
  }
}

多重管道

void callCommandWithPipe(char *argv[], int count)
{
    
   pid_t pid;
  int ret[10];//存放每个管道的下标
  int number=0;//统计管道个数
  for(int i=0;i<count;i++)
  {
    
    if(!strcmp(argv[i],"|"))
    {
    
      ret[number++]=i;
    }
  }
  int cmd_count=number+1;//命令个数
  char* cmd[cmd_count][10];
  for(int i=0;i<cmd_count;i++)//将命令以管道分割存放组数组里
  {
    
    if(i==0)//第一个命令
    {
    
      int n=0;
      for(int j=0;j<ret[i];j++)
      {
    
        cmd[i][n++]=argv[j];
      }
      cmd[i][n]=NULL;
    }
    else if(i==number)//最后一个命令
    {
    
      int n=0;
      for(int j=ret[i-1]+1;j<count;j++)
      {
    
        cmd[i][n++]=argv[j];
      }
      cmd[i][n]=NULL;
    }
    else 
    {
    
       int n=0;
      for(int j=ret[i-1]+1;j<ret[i];j++)
      {
    
        cmd[i][n++]=argv[j];
      }
      cmd[i][n]=NULL;
    }
  }//经过上述操作,我们已经将指令以管道为分隔符分好,下面我们就可以创建管道了
  int fd[number][2];  //存放管道的描述符
  for(int i=0;i<number;i++)//循环创建多个管道
  {
    
    pipe(fd[i]);
  }
  int i=0;
  for(i=0;i<cmd_count;i++)//父进程循环创建多个并列子进程
  {
    
    pid=fork();
    if(pid==0)//子进程直接退出循环,不参与进程的创建
    break;
  }
  if(pid==0)//子进程
  {
    
    if(number)
    {
    
      if(i==0)//第一个子进程
      {
    
        dup2(fd[0][1],1);//绑定写端`  
        close(fd[0][0]);//关闭读端
        //其他进程读写端全部关闭
        for(int j=1;j<number;j++)
        {
    
          close(fd[j][1]);
          close(fd[j][0]);
        }
      }
      else if(i==number)//最后一个进程
      {
    
        dup2(fd[i-1][0],0);//打开读端
        close(fd[i-1][1]);//关闭写端
         //其他进程读写端全部关闭
        for(int j=0;j<number-1;j++)
        {
    
          close(fd[j][1]);
          close(fd[j][0]);
        }
      }
      else //中间进程
      {
    
        dup2(fd[i-1][0],0);//前一个管道的读端打开
        close(fd[i-1][1]);//前一个写端关闭
        dup2(fd[i][1],1);//后一个管道的写端打开
        close(fd[i][0]);//后一个读端关闭
        //其他的全部关闭
        for(int j=0;j<number;j++)
        {
    
             if(j!=i&&j!=(i-1))
             {
    
               close(fd[j][0]);
               close(fd[j][1]);
             }
        }
      }
    }

    execvp(cmd[i][0],cmd[i]);//执行命令
    perror("execvp");
    exit(1);
  }
  //父进程什么都不干,把管道的所有口都关掉
    for(i=0;i<number;i++)
    {
    
        close(fd[i][0]);
        close(fd[i][1]);//父进程端口全部关掉

    }
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
  for(int j=0;j<cmd_count;j++)//父进程等待子进程
  wait(NULL);
}

重定向

>

void mydup(char *argv[])
{
    
  char *strc[MAX] = {
    NULL};
  int i = 0;
  while (strcmp(argv[i], ">"))
  {
    
    strc[i] = argv[i];
    i++;
  }
  int number=i;//重定向前面参数的个数
  int flag =isdo(argv, number);
  i++;
  //出现 echo "adcbe" > test.c  这种情况
  int fdout = dup(1);                                   //让标准输出获取一个新的文件描述符
  int fd = open(argv[i], O_WRONLY | O_CREAT | O_TRUNC,0666); //只写模式|表示如果指定文件不存在,则创建这个文件|表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。
  dup2(fd, 1);
  pid_t pid = fork();
  if (pid < 0)
  {
    
    perror("fork");
    exit(1);
  }
  else if (pid == 0) //子进程
  {
    
    // dup2(fd, 1);
      if (flag == 3) //管道'|'含有管道
      {
    
        callCommandWithPipe(strc, number);
      }
      else
       execvp(strc[0], strc);
  }
  else if (pid > 0)
  {
    
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
    waitpid(pid, NULL, 0);
  }
  dup2(fdout, 1); //
}

>>

void mydup2(char *argv[])
{
    
  char *strc[MAX] = {
    NULL};
  int i = 0;
  
  while (strcmp(argv[i], ">>"))
  {
    
    strc[i] = argv[i];
    i++;
  }
  int number=i;//重定向前面参数的个数
  int flag =isdo(argv, number);
  i++;
  int fdout = dup(1);                                    //让标准输出获取一个新的文件描述符
  int fd = open(argv[i], O_WRONLY | O_CREAT | O_APPEND,0666); //只写模式|表示如果指定文件不存在,则创建这个文件|表示追加,如果原来文件里面有内容,则这次写入会写在文件的最末尾。
  pid_t pid = fork();
   dup2(fd, 1);
  if (pid < 0)
  {
    
    perror("fork");
    exit(1);
  }
  else if (pid == 0) //子进程
  {
    
    if (flag == 3)  //管道'|'含有管道
      {
    
        callCommandWithPipe(strc, number);
      }
      else
       execvp(strc[0], strc);
  }
  else if (pid > 0)
  {
    
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
    waitpid(pid, NULL, 0);
  }
  dup2(fdout, 1); //
}

<

void mydup3(char *argv[])
{
    
  char *strc[MAX] = {
    NULL};
  int i = 0;
  while (strcmp(argv[i], "<"))
  {
    
    strc[i] = argv[i];
    i++;
  }
  i++;
  int number=i;//重定向前面参数的个数
  int flag =isdo(argv, number);
  int fdin = dup(0);                //让标准输出获取一个新的文件描述符
  int fd = open(argv[i], O_RDONLY,0666); //只读模式
   dup2(fd, 0);
  pid_t pid = fork();
  if (pid < 0)
  {
    
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
    perror("fork");
    exit(1);
  }
  else if (pid == 0) //子进程
  {
    
     if (flag == 3)  //管道'|'含有管道
      {
    
        callCommandWithPipe(strc, number);
      }
      else
       execvp(strc[0], strc);
  }
  else if (pid > 0)
  {
    
    waitpid(pid, NULL, 0);
  }
  dup2(fdin, 0);
}

history.h

void ShowHistory()
{
    
  int i = 0;
  HIST_ENTRY **his;
  his = history_list();
  while (his[i] != NULL)
    printf("%-3d   %s\n", i, his[i++]->line);
}

完整代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
char arr[1000]; //用来保存路径
//打印前面那一段提示符
void printname();
#define MAX 128
//解析参数
void commodAnalsy(char *argv[], int number);
int isdo(char *argv[], int count);
// cd命令
void mycd(char *argv[]);
//输出重定向'>'
void mydup(char *argv[]);
//输出重定向'>>'
void mydup2(char *argv[]);
//输入重定向'<'
void mydup3(char *argv[]);
//管道'|'
void mypipe(char *argv[], int count);
//实现多重管道'|'
void callCommandWithPipe(char *argv[], int count);
int pass=0;//标记是否有&
void ShowHistory();
int main()
{
    
  read_history(NULL);
  signal(SIGINT, SIG_IGN);
  signal(SIGHUP, SIG_IGN);
  // char commod[MAX];
  while (1)
  {
    
    char *argv[MAX] = {
    NULL};
    //打印提示符
    printname();
    // commod[0]=0;
    // fgets(commod,MAX,stdin);
    //fflush(stdout);
    char *commod = readline(" ");
    if (commod == NULL) //屏蔽掉ctrl d 出现死循环的情况
    {
    
      printf("\n");
      continue;
    }
    add_history(commod);
    write_history(NULL);
    // commod[strlen(commod)-1]=0;
    if (strlen(commod) == 0) //屏蔽掉ctrl d 出现死循环的情况
    {
    
      // printf("\n");
      continue;
    }

    const char *mark = " "; //分割标识符,用strtok函数以空格为分割标识对字符串commod进行分割,将每个指令取出来.
    int i = 1;
    argv[0] = strtok(commod, mark);
    while (argv[i] = strtok(NULL, mark))
    {
    
      i++;
    }
    // free(commod);
    commodAnalsy(argv, i);
     free(commod);
  }
}
void printname()
{
    
  char *name1 = "gty@gty-Lenovo-Legion";
  printf("\033[1m\033[32m%s\033[0m", name1);
  printf(":");
  getcwd(arr,sizeof(arr));
  printf("\033[1m\033[34m%s\033[0m", arr);
  printf("$ ");
  fflush(stdout); //清空缓冲区,默认为行缓冲,提示符不是以\n结尾的
}
void commodAnalsy(char *argv[], int number)
{
    
  int flag = isdo(argv, number);
  if(pass==1)
  {
    
    number--;
  }
  if (flag == 1)
  {
    
    mycd(argv);
  }
  else if (strcmp(argv[0], "history") == 0)
  {
    
    ShowHistory();
  }
  else if (strcmp(argv[0], "exit") == 0)
  {
    
    printf("exit\n");
    printf("有停止的任务\n");
    exit(0);
  }
  else if (flag == 2) //输出重定向'>'
  {
    
    mydup(argv);
  }
  else if (flag == 3) //管道'|'
  {
    
    callCommandWithPipe(argv, number);
  }
  else if (flag == 4)
  {
    
    mydup2(argv);
  }
  else if (flag == 5)
  {
    
    mydup3(argv);
  }
  else if (flag == 10) //需要子进程进行执行的第三方函数
  {
    
    if (strcmp(argv[0], "ll") == 0)
    {
    
      strcpy(argv[0], "ls");
      argv[number++] = "-l";
    }
    if (strcmp(argv[0], "ls") == 0)
      argv[number++] = "--color=auto";
    pid_t pid = fork();
    if (pid < 0)
    {
    
      perror("fork");
      exit(1);
    }
    else if (pid == 0) //子进程
    {
    
      execvp(argv[0], argv); //执行命令
      perror("commod");
      exit(1);
    }
    else if (pid > 0) //父进程
    {
    
      if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
      waitpid(pid, NULL, 0);
    }
  }
}
char strpwd[MAX]; //用来存放上一次的路劲  实现 cd -
void mycd(char *argv[])
{
    
  if (argv[1] == NULL)
  {
    
    getcwd(strpwd, sizeof(strpwd));
    chdir("/home");
  }
  else if (strcmp(argv[1], "-") == 0)
  {
    
    char strpwd1[MAX];
    getcwd(strpwd1, sizeof(strpwd));
    chdir(strpwd);
    printf("%s\n", strpwd);
    strcpy(strpwd, strpwd1);
  }
  else if (strcmp(argv[1], "~") == 0)
  {
    
    getcwd(strpwd, sizeof(strpwd));
    chdir("/home/gty");
  }
  else
  {
    
    getcwd(strpwd, sizeof(strpwd));
    chdir(argv[1]);
  }
}
void mydup(char *argv[])
{
    
  char *strc[MAX] = {
    NULL};
  int i = 0;
  while (strcmp(argv[i], ">"))
  {
    
    strc[i] = argv[i];
    i++;
  }
  int number=i;//重定向前面参数的个数
  int flag =isdo(argv, number);
  i++;
  //出现 echo "adcbe" > test.c  这种情况
  int fdout = dup(1);                                   //让标准输出获取一个新的文件描述符
  int fd = open(argv[i], O_WRONLY | O_CREAT | O_TRUNC,0666); //只写模式|表示如果指定文件不存在,则创建这个文件|表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。
  dup2(fd, 1);
  pid_t pid = fork();
  if (pid < 0)
  {
    
    perror("fork");
    exit(1);
  }
  else if (pid == 0) //子进程
  {
    
    // dup2(fd, 1);
      if (flag == 3) //管道'|'
      {
    
        callCommandWithPipe(strc, number);
      }
      else
       execvp(strc[0], strc);
  }
  else if (pid > 0)
  {
    
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
    waitpid(pid, NULL, 0);
  }
  dup2(fdout, 1); //
}
void mydup2(char *argv[])
{
    
  char *strc[MAX] = {
    NULL};
  int i = 0;
  
  while (strcmp(argv[i], ">>"))
  {
    
    strc[i] = argv[i];
    i++;
  }
  int number=i;//重定向前面参数的个数
  int flag =isdo(argv, number);
  i++;
  int fdout = dup(1);                                    //让标准输出获取一个新的文件描述符
  int fd = open(argv[i], O_WRONLY | O_CREAT | O_APPEND,0666); //只写模式|表示如果指定文件不存在,则创建这个文件|表示追加,如果原来文件里面有内容,则这次写入会写在文件的最末尾。
  pid_t pid = fork();
   dup2(fd, 1);
  if (pid < 0)
  {
    
    perror("fork");
    exit(1);
  }
  else if (pid == 0) //子进程
  {
    
    if (flag == 3) //管道'|'
      {
    
        callCommandWithPipe(strc, number);
      }
      else
       execvp(strc[0], strc);
  }
  else if (pid > 0)
  {
    
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
    waitpid(pid, NULL, 0);
  }
  dup2(fdout, 1); //
}
void mydup3(char *argv[])
{
    
  char *strc[MAX] = {
    NULL};
  int i = 0;
  while (strcmp(argv[i], "<"))
  {
    
    strc[i] = argv[i];
    i++;
  }
  i++;
  int number=i;//重定向前面参数的个数
  int flag =isdo(argv, number);
  int fdin = dup(0);                //让标准输出获取一个新的文件描述符
  int fd = open(argv[i], O_RDONLY,0666); //只读模式
   dup2(fd, 0);
  pid_t pid = fork();
  if (pid < 0)
  {
    
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
    perror("fork");
    exit(1);
  }
  else if (pid == 0) //子进程
  {
    
     if (flag == 3) //管道'|'
      {
    
        callCommandWithPipe(strc, number);
      }
      else
       execvp(strc[0], strc);
  }
  else if (pid > 0)
  {
    
    waitpid(pid, NULL, 0);
  }
  dup2(fdin, 0);
}
void callCommandWithPipe(char *argv[], int count)
{
    
   pid_t pid;
  int ret[10];//存放每个管道的下标
  int number=0;//统计管道个数
  for(int i=0;i<count;i++)
  {
    
    if(!strcmp(argv[i],"|"))
    {
    
      ret[number++]=i;
    }
  }
  int cmd_count=number+1;//命令个数
  char* cmd[cmd_count][10];
  for(int i=0;i<cmd_count;i++)//将命令以管道分割存放组数组里
  {
    
    if(i==0)//第一个命令
    {
    
      int n=0;
      for(int j=0;j<ret[i];j++)
      {
    
        cmd[i][n++]=argv[j];
      }
      cmd[i][n]=NULL;
    }
    else if(i==number)//最后一个命令
    {
    
      int n=0;
      for(int j=ret[i-1]+1;j<count;j++)
      {
    
        cmd[i][n++]=argv[j];
      }
      cmd[i][n]=NULL;
    }
    else 
    {
    
       int n=0;
      for(int j=ret[i-1]+1;j<ret[i];j++)
      {
    
        cmd[i][n++]=argv[j];
      }
      cmd[i][n]=NULL;
    }
  }//经过上述操作,我们已经将指令以管道为分隔符分好,下面我们就可以创建管道了
  int fd[number][2];  //存放管道的描述符
  for(int i=0;i<number;i++)//循环创建多个管道
  {
    
    pipe(fd[i]);
  }
  int i=0;
  for(i=0;i<cmd_count;i++)//父进程循环创建多个并列子进程
  {
    
    pid=fork();
    if(pid==0)//子进程直接退出循环,不参与进程的创建
    break;
  }
  if(pid==0)//子进程
  {
    
    if(number)
    {
    
      if(i==0)//第一个子进程
      {
    
        dup2(fd[0][1],1);//绑定写端`  
        close(fd[0][0]);//关闭读端
        //其他进程读写端全部关闭
        for(int j=1;j<number;j++)
        {
    
          close(fd[j][1]);
          close(fd[j][0]);
        }
      }
      else if(i==number)//最后一个进程
      {
    
        dup2(fd[i-1][0],0);//打开读端
        close(fd[i-1][1]);//关闭写端
         //其他进程读写端全部关闭
        for(int j=0;j<number-1;j++)
        {
    
          close(fd[j][1]);
          close(fd[j][0]);
        }
      }
      else //中间进程
      {
    
        dup2(fd[i-1][0],0);//前一个管道的读端打开
        close(fd[i-1][1]);//前一个写端关闭
        dup2(fd[i][1],1);//后一个管道的写端打开
        close(fd[i][0]);//后一个读端关闭
        //其他的全部关闭
        for(int j=0;j<number;j++)
        {
    
             if(j!=i&&j!=(i-1))
             {
    
               close(fd[j][0]);
               close(fd[j][1]);
             }
        }
      }
    }

    execvp(cmd[i][0],cmd[i]);//执行命令
    perror("execvp");
    exit(1);
  }
  //父进程什么都不干,把管道的所有口都关掉
    for(i=0;i<number;i++)
    {
    
        close(fd[i][0]);
        close(fd[i][1]);//父进程端口全部关掉

    }
     if(pass==1)
      {
    
        pass=0;
        printf("%d\n",pid);
        return;
      }
  for(int j=0;j<cmd_count;j++)//父进程等待子进程
  wait(NULL);
}

int isdo(char *argv[], int count)
{
    
  int flag = 10, i;
  if (argv[0] == NULL)
    return 0;
  if (strcmp(argv[0], "cd") == 0)
  {
    
    flag = 1;
  }
  for (i = 0; i < count; i++)
  {
    
    if (strcmp(argv[i], ">") == 0)
      flag = 2;
    if (strcmp(argv[i], "|") == 0)
      flag = 3;
    if (strcmp(argv[i], ">>") == 0)
      flag = 4;
    if (strcmp(argv[i], "<") == 0)
      flag = 5;
    if (strcmp(argv[i], "<<") == 0)
      flag = 6;
    if (strcmp(argv[i], "&") == 0)
    {
    
        pass = 1;
        argv[i]=NULL;
    }
  }
  return flag;
}
void ShowHistory()
{
    
  int i = 0;
  HIST_ENTRY **his;
  his = history_list();
  while (his[i] != NULL)
    printf("%-3d   %s\n", i, his[i++]->line);
}
相关文章
|
25天前
|
Unix Linux 程序员
Linux文本搜索工具grep命令使用指南
以上就是对Linux环境下强大工具 `grep` 的基础到进阶功能介绍。它不仅能够执行简单文字查询任务还能够处理复杂文字处理任务,并且支持强大而灵活地正则表达规范来增加查询精度与效率。无论您是程序员、数据分析师还是系统管理员,在日常工作中熟练运用该命令都将极大提升您处理和分析数据效率。
100 16
|
17天前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
|
3月前
|
监控 Linux 网络安全
Linux命令大全:从入门到精通
日常使用的linux命令整理
663 13
|
4月前
|
Linux 网络安全 数据安全/隐私保护
使用Linux系统的mount命令挂载远程服务器的文件夹。
如此一来,你就完成了一次从你的Linux发车站到远程服务器文件夹的有趣旅行。在这个技术之旅中,你既探索了新地方,也学到了如何桥接不同系统之间的距离。
549 21
|
4月前
|
JSON 自然语言处理 Linux
linux命令—tree
tree是一款强大的Linux命令行工具,用于以树状结构递归展示目录和文件,直观呈现层级关系。支持多种功能,如过滤、排序、权限显示及格式化输出等。安装方法因系统而异常用场景包括:基础用法(显示当前或指定目录结构)、核心参数应用(如层级控制-L、隐藏文件显示-a、完整路径输出-f)以及进阶操作(如磁盘空间分析--du、结合grep过滤内容、生成JSON格式列表-J等)。此外,还可生成网站目录结构图并导出为HTML文件。注意事项:使用Tab键补全路径避免错误;超大目录建议限制遍历层数;脚本中推荐禁用统计信息以优化性能。更多详情可查阅手册mantree。
linux命令—tree
|
2月前
|
Linux 网络安全 开发工具
技术栈:这50条最常用的 Linux 命令你一定要会!
建议多在终端中实践,遇到不懂的命令就用 man 或 --help 了解详情!
394 0
|
4月前
|
监控 Linux
Linux系统中使用df命令详解磁盘使用情况。
`df`命令是Linux系统管理员和用户监控和管理磁盘空间使用的重要工具。掌握它的基本使用方法和选项可以帮助在必要时分析和解决空间相关问题。简洁但功能丰富,`df`命令确保了用户可以快速有效地识别和管理文件系统的空间使用情况。
260 13
|
2月前
|
安全 Linux Shell
Linux系统中sudo命令的高效运用技巧。
用户可以通过sudo -l来列出自己目前可执行的命令列表,这有助于用户了解自己的权限范围。
118 0
|
2月前
|
监控 Linux Shell
linux命令
常用 Linux 命令汇总
|
4月前
|
Unix Linux
linux命令—cd
`cd` 命令是 Linux/Unix 系统中用于切换工作目录的基础命令。支持相对路径与绝对路径,常用选项如 `-L` 和 `-P` 分别处理符号链接的逻辑与物理路径。实际操作中,可通过 `cd ..` 返回上级目录、`cd ~` 回到家目录,或利用 `cd -` 在最近两个目录间快速切换。结合 Tab 补全和 `pwd` 查看当前路径,能显著提升效率。此外,需注意特殊字符路径的正确引用及脚本中绝对路径的优先使用。