[关闭]
@Lxjeng 2016-04-26T12:14:44.000000Z 字数 2649 阅读 921

实验二 Linux 进程管理

  • 姓名:梁晓静 学号:1405010530

1、实验题目

  • 实现一个简单的shell(命令行解释器)

2、实验目的

  • 在Linux系统下,通过c语言编程完成一个自己的shell

3、实验平台

  • Linux系统虚拟机

4、实验要求

你的 shell 类似于 sh,bash,csh 等,必须支持以下内部命令:

  • cd <目录>:更改当前的工作目录到另一个<目录>。如果<目录>未指定,输出当前工作目录。如果<目录>不存在,应当有适当的错误信息提示。这个命令应该也能改变 PWD 的环境变量。
  • environ:出所有环境变量字符串的设置(类似于 Unix系统下的env命令)。
  • echo <内容 >:显示 echo 后的内容且换行。
  • help:简短概要的输出你的 shell 的使用方法和基本功能。
  • jobs:输出 shell当前的一系列子进程,必须提供子进程的命名和PID号。
  • quit,exit,bye:退出 shell。

5、实验内容和步骤

①编写shell程序:

此处输入图片的描述

②运行各命令行:

此处输入图片的描述
此处输入图片的描述
此处输入图片的描述

5、程序清单

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <sys/wait.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <errno.h>
  8. #include <sys/stat.h>
  9. void help()
  10. {
  11. printf( " 帮助\n"
  12. " 命令 功能\n"
  13. " cd 更改当前的工作目录到另一个<目录>\n"
  14. " environ 列出所有环境变量字符串的设置\n"
  15. " echo 显示echo后面的内容并换行\n"
  16. " help 显示帮助信息\n"
  17. " jobs 输出shell当前的一系列子进程,包括子进程的命名和PID号\n"
  18. " ls 显示当前目录的所有文件\n"
  19. " quit|exit|bye 退出shell\n");
  20. }
  21. int main()
  22. {
  23. char n[100];
  24. pid_t pid;
  25. char buf1[1024],buf2[1024];
  26. int i=0;
  27. char *p;
  28. int argc=0;
  29. char *argv[10];
  30. while(1)
  31. {
  32. argc=0; //参数个数初始化为0
  33. for(i=0; i<10; i++)
  34. {
  35. argv[i]=NULL;//字符串数组赋初值
  36. }
  37. memset(n,0,100);//数组清零(将n数组的前100个字节用0替换)
  38. char *username=getenv("USER");
  39. gethostname(buf1,sizeof buf1);//返回本地主机的标准主机名
  40. getwd(buf2); //获取当前路径
  41. strtok(buf1,"");
  42. printf("%s@%s %s $ ",username,buf1,buf2);
  43. fgets(n,100,stdin);
  44. n[strlen(n)-1]=0;
  45. p=strtok(n," "); //根据空格分开,并获得头指令
  46. while(p&&argc<10)
  47. {
  48. argv[argc]=p;
  49. p=strtok(NULL," ");
  50. argc++;
  51. }
  52. if(argc<10)
  53. {
  54. argv[argc]=NULL;
  55. } //字符截取
  56. if(!strcmp(argv[0],"exit")||!strcmp(argv[0],"quit")||!strcmp(argv[0],"bye"))
  57. break;
  58. else if(!strcmp(argv[0],"cd"))
  59. {
  60. if(chdir(argv[1])<0)
  61. printf(" 打开失败!\n");
  62. }
  63. else if(!strcmp(argv[0],"ls"))
  64. {
  65. if((pid=fork())<0)
  66. {
  67. printf(" fork error\n");
  68. exit(0);
  69. }
  70. else if(pid==0)
  71. {
  72. if(execl("/bin/ls","ls",NULL)<0);
  73. printf(" execl error\n");
  74. exit(0);
  75. }
  76. waitpid(pid,0,0);
  77. }
  78. else if(!strcmp(argv[0],"echo"))
  79. {
  80. printf("%s\n",argv[1]);
  81. }
  82. else if(!strcmp(argv[0],"help"))
  83. help();
  84. else if(!strcmp(argv[0],"env"))
  85. {
  86. if((pid=fork())<0)
  87. {
  88. printf(" fork error\n");
  89. exit(0);
  90. }
  91. else if(pid==0)
  92. {
  93. if(execl("/bin/env","env",NULL)<0)
  94. printf(" execl error\n");
  95. exit(0);
  96. }
  97. waitpid(pid,0,0);
  98. }
  99. else if(!strcmp(argv[0],"jobs"))
  100. system("ps"); //调用ps函数查看子进程
  101. }
  102. return 0;
  103. }

6、实验体会

  • 1、本实验的关键在于shell源码的编写,一开始无从下手,直接在百度上搜的又不全面,但是通过对其中一段代码的学习,大致思路便清晰了,也理解了如fork,memset,strtok,chdir等函数的功能和用法。
  • 2、关键思路在于输入命令行与相应字符串对比,如果相等就执行。此时用到strcmp函数,如果两个字符串相等就返回0,所以就决定了if语句中的判断条件。实验用到argv[]字符串数组,argv[0]存储命令行字符,argv【1】存储相应目录名和内容。通过strtok函数进行字符串截取,cd中,当argv【1】<0表示输入为空,此时显示“打开失败!”。echo中,直接通过printf函数输出argv【1】表示的内容。
  • 3、在 Linux 中创建子进程要使用fork()函数,执行新的命令要使用exec()系列函数,这里使用execl(const char *path, const char *arg,...)函数,const char *arg以及省略号代表的参数可被视为arg0,arg1,...,argn.他们合起来描述了指向NULL结尾的字符串的指针列表,即执行程序的参数列表.作为约定,第一个 arg 参数应该指向执行程序名自身,参数列表必须用 NULL 指针结束. shell等待子进程结束才能执行新的命令,所以使用waitpid()函数,结束终止进程使用 exit()函数。
  • 4、好吧,代码是借鉴班上大神的,不过我改成了字符串截取然后进行比较,而不是直接通过输入字符串数组n进行操作。花了很久差不多把每行代码都弄懂,一开始最大的误解,我以为每个命令行都要自己去编写代码实现功能,其实是可以调用系统自身就有的!
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注