zoukankan      html  css  js  c++  java
  • 简单的外壳(shell)

    写在前面的

    很多人在csdn上分享了自己的面试经验,其中笔试值得一提。公司笔试的题目有些比较基础但是又是比较核心的概念。就比如,什么是线程,什么是多线程,什么是进程,什么是多进程,线程和进程有什么区别!!

    这题目一上眼,脑子中一晃就一个印象:看过很多次了,但是就是说不明白他是什么东西了。

    线程是进程中的一个单一控制流;一个进程可能完成很大的任务,多线程即一个进程中有多个线程,每个线程完成不同的工作,这样就提高了程序运行的速度。进程是运行中的程序,它是与线程的区别是进程有独立的代码,数据和存储空间,但是线程可以共享数据空间,而每个线程有独立的执行堆栈和程序计数器。

    概念是很清楚的,非得理解并记住不可,不然以后应聘跟头有的栽。

    废话不多说了。

    外壳简介

    1212979936272_000

    外壳是什么,在刚上大学的时候就有听到这个形象的

    在linux或者unix,可能很多人都接触过ubuntu或者red hat之类的有良好图形界面的linux,在字符界面下ls,cd,或者grep等等来完成想要完成的操作,这些都是一个个程词汇,说形像,可能它不可能简单到就是一个蜗牛贝壳的外壳吧… 

    序,而接受输入的命令(命令后可能会有参数列表)就是外壳,但是外壳也不是很神秘。

     为了方便与操作系统交互,外壳诞生了。外壳是一个交互型的应用级程序,所以外壳也是一个程序,它隐藏了很多操作系统底层的细节操作,它代表用户运行了其他的程序。

    有了“外壳”的称谓,那外壳里面也应该有名副其实的东西,不可能是个空壳吧。没错,在外壳之下就是kernel(内核),这才是操作系统实实在

    在的东西,与底层硬件交互着。 

    (插入外壳解释图) 

     images (1)

     images

    linux下是这样,win下也有类似的东西,此时它的外壳就是我们熟悉的dos界面啦,cmd.exe。把重点放在linux上,win上的东西也是大同小异的。

    linux下的fork和execve

    在linux下的c编程,fork,execve函数很常见的。fork函数一式两份复制了父进程也就是当前进程,创建了子进程,新建的子进程与父进程几乎完全一样,唯一的不同是他们的标识进程id,即PID。
    (插入fork的描述图)image

    execve函数加载并运行可执行目标文件,注意它是在当前进程的上下文当中加载并欲行一个新的进程,当前进程的地址空间会被新建的进程覆盖,与fork不同,它并没有创建新的进程,新加载和运行的进程与此前的进程有着相同的进程id。
    (插入execve的描述图)image

       
    linux中采用了这些函数,集成了父子进程这样一种关系,一个简单的外壳就是这样的,为什么说是简单的外壳?因为里面还涉及了很多复杂的设计,但是核心的东西是这些而已。下面是简单的外壳,参照了《深入理解计算机系统》。
     

    简单外壳设计

    环境:linux,vim编辑器,gcc编译器。
    除了main函数,还有其他的三个函数,eval函数调用praseline函数来解释命令行参数,并会将结果传递给execve来执行。第一个参数可以是内置的命令或者可执行目标文件。如果是前者,那么就直接解释执行,为了简化外壳,就只内置了“q”命令,退出;如果是后者,那么调用fork创建子进程,execve在该子进程的上下文中加载并执行这个文件。

    来测试一下,方便测试,在这个外壳所属目录下放了一个简单的hello可执行目标文件:
    测试1:

    1
    测试2:

    2
    测试3:

    3

    简单的外壳还可以添加Tab键补全命令或者目录的功能。最大的缺陷就是父进程不对子进程进行回收,在unix中。当子进程结束的时候,其所属的代码数据空间都仍然存留在内存当中,等待父进程对其进行回收。

    下面是代码:

    View Code
    #include <stdlib.h> 
    #include <stdio.h> 
    #include <sys/types.h> 
    #include <string.h> 

    #define MAXLINE 128 
    #define MAXARGVS 6 

    void eval(char * cmdline) 

        char * argv[MAXARGVS]; 
        char buf[MAXLINE]; 
        int bg; 
        pid_t pid; 

        strcpy(buf,cmdline); 
        bg = parseline(buf,argv); 

        if(argv[0]==NULL) 
            return

        if(!builtin_command(argv)) 
        { 
            if((pid=fork()==0)) 
            { 
                if(execve(argv[0],argv,0)<0
                { 
                    printf("%s:command not found .\n",argv[0]); 
                    exit(0); 
                } 
            } 

            if(!bg) 
            { 
                int status;        //status for waitpid 
                if(waitpid(pid,&status,0)<0
                    printf("waitpid error"); 
            } 
            else 
                printf("%d %s",pid,cmdline); 
        } 
        return


    int parseline(char * buf,char ** argv) 

        char * delimiter; 
        int argc; //argv counter; 
        int bg; 

        buf[strlen(buf)-1] = ' '
        while(*buf && (*buf==' '))    //check the cmd 
            buf++; 

        argc = 0
        while((delimiter = strchr(buf,' '))) 
        { 
            argv[argc++] = buf; 
            *delimiter = '\0'
            buf = delimiter + 1
            while(*buf && (*buf==' '))    //ignore blanks 
                buf++; 
        } 
        argv[argc] = NULL; 

        if(argc==0
            return 1

        if((bg=(*argv[argc-1]=='&')) != 0
            argv[--argc] = NULL; 

        return bg; 



    int builtin_command(char ** argv) 

        if(!strcmp(argv[0],"q")) 
            exit(0); 
        else if(!strcmp(argv[0],"&")) 
            return 1
        return 0


    int main() 

        char cmdline[MAXLINE]; 
        while(1
        { 
            printf("shell> :"); 
            fgets(cmdline,MAXLINE,stdin); 

            if(feof(stdin)) 
                exit(0); 

            eval(cmdline); 
        } 
        return 1
    }

    题外话

    题外话:如何在linux中挂载U盘,方便虚拟机和PC机之间的数据传输?
    首先linux要对u盘等外设做出必要的中断或者反应
    fdisk -l 可以看到相关的信息
    21
    如果是fat16的u盘就使用下面的命令,/mnt/usb可能不存在,可以创建。
    mount -t msdos /dev/sdc1 /mnt/usb
    如果是fat32的盘
    mount -t vfat /dev/sdc1 /mnt/usb
    如果是ext2格式,就用命令:
    mount -t ext2 /dev/sdc1 /mnt/usb

    如果无出错提示,那么挂载成功,可以对u盘内容进行管理(cp,rm等)。

    本文完。

    捣乱小子 2012年2月23日

    原文链接:http://www.cnblogs.com/daoluanxiaozi/archive/2012/02/23/2365513.html

  • 相关阅读:
    Foj1675数论
    JSTL与EL之间的千丝万缕
    2013多校联合2 I Warm up 2(hdu 4619)
    ios视图切换之push与present混用
    Ruby设计模式透析之 —— 适配器(Adapter)
    晓说智能指针shared_ptr为何可以实现跨模块分配和释放内存
    CSS的力量
    MySQL-select 1;
    MySQL数据库-语言简介
    Eclipse开发工具提交代码
  • 原文地址:https://www.cnblogs.com/daoluanxiaozi/p/2365513.html
Copyright © 2011-2022 走看看