编写自己的shell(2)
来源:互联网 发布:知之者 编辑:程序博客网 时间:2024/06/03 18:58
脚本中除了命令之外还包括以下元素:变量,用户输入,控制流,环境变量。
上一次用fork,execvp,wait实现了一个能够创建进程和运行程序的shell。此次对这个shell做一些改进。加入命令行解析,这样用户可以在一行中输入命令和所有参数了,然后将控制语句if...then加入到这个shell中,最后加入局部变量和环境变量。本次先加入第一个功能。
第一个改进是添加命令行解析的功能。用户可在一行中输入 比如: find /home -name core -mtime +3 -print
然后由解析器将命令行拆成字符串数组,以便传给execvp。在shell中忽略信号SIGINT和SIGQUIT,但是在子进程中恢复对信号SIGINT和SIGQUIT的默认操作,允许用户通过按表示结束文件的Ctrl-D来退出。此版本命名为smsh1.其shell的主函数如下:
int main(){char*cmdline, *prompt, **arglist;intresult;voidsetup();prompt = DFL_PROMPT ;setup();while ( (cmdline = next_cmd(prompt, stdin)) != NULL ){if ( (arglist = splitline(cmdline)) != NULL ){result = execute(arglist);freelist(arglist);}free(cmdline);}return 0;}其中3个函数解释:
1.next_cmd 从输入流读入下一个命令。它调用malloc来分配内存以接受任意长度的命令行。碰到文件结束符,它返回NULL。
2.splitline 将一个字符串分解为字符串数组,并返回这个数组。它调用malloc来分配内存以接受任意参数个数的命令行。此数组以NULL标记结束。
3.execute 运行一个命令,返回命令的结束状态。
smsh1由三个文件组成 smsh1.c ,splitline.c,execute.c
三者代码如下:
smsh1.c:
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<signal.h>#include"smsh.h"#defineDFL_PROMPT"> "int main(){char*cmdline, *prompt, **arglist;intresult;voidsetup();prompt = DFL_PROMPT ;setup();while ( (cmdline = next_cmd(prompt, stdin)) != NULL ){if ( (arglist = splitline(cmdline)) != NULL ){result = execute(arglist);freelist(arglist);}free(cmdline);}return 0;}void setup()/* * purpose: initialize shell * returns: nothing. calls fatal() if trouble */{signal(SIGINT, SIG_IGN);signal(SIGQUIT, SIG_IGN);}void fatal(char *s1, char *s2, int n){fprintf(stderr,"Error: %s,%s\n", s1, s2);exit(n);}
splitline.c:
#include<stdio.h>#include<stdlib.h>#include<string.h>#include"smsh.h"char * next_cmd(char *prompt, FILE *fp){char*buf ; /* the buffer*/intbufspace = 0;/* total size*/intpos = 0;/* current position*/intc;/* input char*/printf("%s", prompt);/* prompt user*/while( ( c = getc(fp)) != EOF ) {/* need space? */if( pos+1 >= bufspace ){/* 1 for \0*/if ( bufspace == 0 )/* y: 1st time*/buf = emalloc(BUFSIZ);else/* or expand*/buf = erealloc(buf,bufspace+BUFSIZ);bufspace += BUFSIZ;/* update size*/}/* end of command? */if ( c == '\n' )break;/* no, add to buffer */buf[pos++] = c;}if ( c == EOF && pos == 0 )/* EOF and no input*/return NULL;/* say so*/buf[pos] = '\0';return buf;}#defineis_delim(x) ((x)==' '||(x)=='\t')char ** splitline(char *line){char*newstr();char**args ;intspots = 0;/* spots in table*/intbufspace = 0;/* bytes in table*/intargnum = 0;/* slots used*/char*cp = line;/* pos in string*/char*start;intlen;if ( line == NULL )/* handle special case*/return NULL;args = emalloc(BUFSIZ);/* initialize array*/bufspace = BUFSIZ;spots = BUFSIZ/sizeof(char *);while( *cp != '\0' ){while ( is_delim(*cp) )/* skip leading spaces*/cp++;if ( *cp == '\0' )/* quit at end-o-string*/break;/* make sure the array has room (+1 for NULL) */if ( argnum+1 >= spots ){args = erealloc(args,bufspace+BUFSIZ);bufspace += BUFSIZ;spots += (BUFSIZ/sizeof(char *));}/* mark start, then find end of word */start = cp;len = 1;while (*++cp != '\0' && !(is_delim(*cp)) )len++;args[argnum++] = newstr(start, len);}args[argnum] = NULL;return args;}/* * purpose: constructor for strings * returns: a string, never NULL */char *newstr(char *s, int l){char *rv = emalloc(l+1);rv[l] = '\0';strncpy(rv, s, l);return rv;}void freelist(char **list)/* * purpose: free the list returned by splitline * returns: nothing * action: free all strings in list and then free the list */{char**cp = list;while( *cp )free(*cp++);free(list);}void * emalloc(size_t n){void *rv ;if ( (rv = malloc(n)) == NULL )fatal("out of memory","",1);return rv;}void * erealloc(void *p, size_t n){void *rv;if ( (rv = realloc(p,n)) == NULL )fatal("realloc() failed","",1);return rv;}
/* execute.c - code used by small shell to execute commands */#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<signal.h>#include<sys/wait.h>int execute(char *argv[])/* * purpose: run a program passing it arguments * returns: status returned via wait, or -1 on error * errors: -1 on fork() or wait() errors */{intpid ;intchild_info = -1;if ( argv[0] == NULL )/* nothing succeeds*/return 0;if ( (pid = fork()) == -1 )perror("fork");else if ( pid == 0 ){signal(SIGINT, SIG_DFL);signal(SIGQUIT, SIG_DFL);execvp(argv[0], argv);perror("cannot execute command");exit(1);}else {if ( wait(&child_info) == -1 )perror("wait");}return child_info;}
smsh.h:
#defineYES1#defineNO0char*next_cmd();char**splitline(char *);voidfreelist(char **);void*emalloc(size_t);void*erealloc(void *, size_t);intexecute(char **);voidfatal(char *, char *, int );intprocess();
编译运行:
$ gcc smsh1.c splitline.c execute.c -o smsh1
$ ./smsh1
>ps -f
UID PID PPID C STIME TTY TIME CMD
sk 3982 3972 0 19:49 pts/0 00:00:00 bash
sk 4637 3982 0 20:11 pts/0 00:00:00 ./smsh1
sk 4638 4637 0 20:11 pts/0 00:00:00 ps -f
>这里按Ctrl-D键
$
其中ps -f是./smsh1的子进程,./smsh1是bash的子进程.
- 编写自己的shell(2)
- 自己编写的linux shell (修改)
- 编写自己的shell(3)
- 自己编写简单的shell
- linux 编写自己的shell
- 自己编写的简单shell
- APUE进程控制>>编写自己的shell(1)
- 编写自己的Shell解释器
- 如何保护自己编写的shell程序
- 编写自己的Shell解释器
- 编写自己的Shell解释器
- 编写自己的Shell解释器
- 编写自己的Shell解释器
- 编写自己的Shell解释器
- 编写自己的Shell解释器
- 编写自己的Shell解释器
- 编写自己的shell 精简版
- 编写自己的Shell解释器
- K-Means算法
- hibernate Criteria setProjection
- ACM-简单题之Delta-wave——hdu1030
- unity3d 之-error记
- NYOJ-91
- 编写自己的shell(2)
- 贪吃蛇游戏
- Morgan Stanley Programming Constest 2014题目Free Fall
- ARM汇编--pc 跳转方法
- 网络存储学习之SAN
- 【算法】堆排序
- 数据结构随手笔记之哈希表
- 百度云推送
- 二维背包(hdu2159)