• Ubuntu下Shell的简单实现(C语言)


        最近在操作系统的实验课上要求在Linux下实现Shell的简单功能,做了实验感觉挺有收获的,就在这分享一下,欢迎指出问题。

      废话不多说,先看main()函数。

     1 int main()  
     2 {  
     3     char inputBuffer[MAXLINE];  
     4     char *argv[MAXLINE/2 - 1];  
     5   
     6     while (1)  
     7     {  
     8         printf("COMMAND->");  
     9         fgets(inputBuffer,80,stdin); 
    10         setup(inputBuffer, argv);  
    11   
    12     }  
    13     return 0;  
    14 }

        main函数中,通过fgets(inputBuffer,80,stdin)函数获得用户的输入,并通过setup(inputBuffer,argv)函数分割输入的字串,将命令语句和参数分别提取出来。这里用到了fgets()函数,说一下用fgets(inputBuffer,80,stdin)、gets(inputBuffer)的不同,这会影响到接下来setup函数的写法。

        gets()函数用来从标准输入设备(键盘)读取字符串直到换行符结束,但换行符会被丢弃,然后在末尾添加''字符。注意在c中需要加头文件#include<string.h>,在c++中不需要。

        fgets函数用来从文件中读入字符串。fgets函数的调用形式如下:fgets(str,n,fp);此处,fp是文件指针;str是存放在字符串的起始地址;n是一个int类型变量。函数的功能是从fp所指文件中读入n-1个字符放入str为起始地址的空间内;如果在未读满n-1个字符之时,已读到一个换行符或一个EOF(文件结束标志),则结束本次读操作,读入的字符串中最后包含读到的换行符。因此,确切地说,调用fgets函数时,最多只能读入n-1个字符。读入结束后,系统将自动在最后加'',并以str作为函数值返回。

        也就是说我们在输入命令行,例如“ls”的时候,输入完之后会按下一个回车执行,用gets的话,那么存在inputBuffer中的字符串为“ls”换行符是要被丢弃的,但是如果使用fget函数的话,那么读取的字符串为“ls ”,换行符是不会被丢弃的,这一点一定要注意。

        接下来看fget函数:

     1 //p是一个全局char型指针char *p
     2 void setup(char inputBuffer[], char *argv[])  
     3 {  
     4     int i, j;  
     5     i = 0;  
     6     for(p = inputBuffer;*p!='' ;p++)//输入字符分开
     7     {  
     8         argv[i++] = p; 
     9         while(*p != ' ' && *p != '' && *p != '
    ')  
    10             p++;  
    11 
    12         *p = '';  
    13     }  
    14     argv[i] = NULL;//参数要以NULL为结尾
    15 
    16     pid_t pid;
    17     pid = fork();//创建子进程
    18 
    19     if(pid == 0)//子进程对输入命令操作
    20     {  
    21              execvp(argv[0], argv);     
    22         printf("command error
    ");//execvp返回-1,执行失败,命令有错误
    23     }  
    24   
    25     else if( pid > 0 )//父进程
    26     {  
    27      wait(NULL);//父进程等待子进程结束,回收子进程  
    28     }  
    29   
    30     else  
    31     {  
    32      printf("fork error
    ");  
    33     }  
    34 }

         execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用数组指针来传递给执行文件,并且必须以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。

         因此首先将命令行和参数分隔开来,分别传入execve函数中去执行,但是要注意的是获取用户的字符串输入用的是fgets,那么在最后肯定是有一个换行符的,如果不舍弃掉这个换行符的话,例如输入的是'ls'命令,那么传入arg[0]指向'ls'的首地址,arg[1]指向',argv[2]指向'NULL',execve函数在执行到arg[1]的时候便会停止,没有执行到NULL,会报错,因此在使用fgets函数的时候要舍弃掉最后的一个换行符。

         execvp如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。由于执行成功了,这个进程就结束了,也代表这个程序也完了,所以它不会返回至主程序,这就是要创建子进程的原因,执行命令在子进程中,父进程负责函数的返回。

    参考文章:http://blog.csdn.net/lishuhuakai/article/details/11928055

  • 相关阅读:
    很多人都没用过的轻量级Oracle数据库数据导出工具SQLLDR2——性能超赞
    IT人员必备linux安全运维之Ssh用途、安全性、身份认证以及配置……【转】
    ps aux排序
    Oracle-AWR报告简介及如何生成【转】
    MySQL删除数据几种情况以及是否释放磁盘空间【转】
    MySQL登录问题1045 (28000)处理步骤【原创】
    nginx与PHP的关系和交互方式【转】
    MySQL常见错误代码说明
    xargs -i 和-I 的区别【转】
    linux中的计算【转】
  • 原文地址:https://www.cnblogs.com/yangrenzhi/p/4986080.html
Copyright © 2020-2023  润新知