简单的外壳(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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值