《Unix/Linux编程实践教程》第九章将第八章所编的shell做进一步的完善,包括:
1)加入命令行解析,方便用户在一行里输完命令和所有参数
2)加入if..else..控制语句
3)加入局部变量和环境变量
对于上章后面的练习题(解决SIGINT信号杀死shell的BUG),本章也给出了解决方案,简单流程如下:
在shell中忽略SIGINT和SIGQUIT,在子进程中对恢复信号的默认操作。
相关阅读:
Unix/Linux编程实践教程【高清PDF中文版+附录光盘+代码】:
代码如下,一共4个文件:
smsh.h:
1: #define YES 1 2: #define NO 0 3: 4: char *next_cmd(); 5: char **splitline(char *); 6: void freelist(char **); 7: void *emalloc(size_t); 8: void *erealloc(void *, size_t); 9: int execute(char **); 10: void fatal(char *, char *, int ); 11: 12: int process();smsh1.c:
1: /** smsh1.c small-shell version 1 2: ** first really useful version after prompting shell 3: ** this one parses the command line into strings 4: ** uses fork, exec, wait, and ignores signals 5: **/ 6: 7: #include <stdio.h> 8: #include <stdlib.h> 9: #include <unistd.h> 10: #include <signal.h> 11: #include "smsh.h" 12: 13: #define DFL_PROMPT "> " 14: 15: int main() 16: { 17: char *cmdline, *prompt, **arglist; 18: int result; 19: void setup(); 20: 21: prompt = DFL_PROMPT ; 22: setup(); 23: 24: while ( (cmdline = next_cmd(prompt, stdin)) != NULL ){ 25: if ( (arglist = splitline(cmdline)) != NULL ){ 26: result = execute(arglist); 27: freelist(arglist); 28: } 29: free(cmdline); 30: } 31: return 0; 32: } 33: 34: void setup() 35: /* 36: * purpose: initialize shell 37: * returns: nothing. calls fatal() if trouble 38: */ 39: { 40: signal(SIGINT, SIG_IGN); 41: signal(SIGQUIT, SIG_IGN); 42: } 43: 44: void fatal(char *s1, char *s2, int n) 45: { 46: fprintf(stderr,"Error: %s,%s/n", s1, s2); 47: exit(n); 48: } 49: 50:splitline.c:
1: /* splitline.c - commmand reading and parsing functions for smsh 2: * 3: * char *next_cmd(char *prompt, FILE *fp) - get next command 4: * char **splitline(char *str); - parse a string 5: 6: */ 7: 8: #include <stdio.h> 9: #include <stdlib.h> 10: #include <string.h> 11: #include "smsh.h" 12: 13: char * next_cmd(char *prompt, FILE *fp) 14: /* 15: * purpose: read next command line from fp 16: * returns: dynamically allocated string holding command line 17: * errors: NULL at EOF (not really an error) 18: * calls fatal from emalloc() 19: * notes: allocates space in BUFSIZ chunks. 20: */ 21: { 22: char *buf ; /* the buffer */ 23: int bufspace = 0; /* total size */ 24: int pos = 0; /* current position */ 25: int c; /* input char */ 26: 27: printf("%s", prompt); /* prompt user */ 28: while( ( c = getc(fp)) != EOF ) { 29: 30: /* need space? */ 31: if( pos+1 >= bufspace ){ /* 1 for /0 */ 32: if ( bufspace == 0 ) /* y: 1st time */ 33: buf = emalloc(BUFSIZ); 34: else /* or expand */ 35: buf = erealloc(buf,bufspace+BUFSIZ); 36: bufspace += BUFSIZ; /* update size */ 37: } 38: 39: /* end of command? */ 40: if ( c == '/n' ) 41: break; 42: 43: /* no, add to buffer */ 44: buf[pos++] = c; 45: } 46: if ( c == EOF && pos == 0 ) /* EOF and no input */ 47: return NULL; /* say so */ 48: buf[pos] = '/0'; 49: return buf; 50: } 51: 52: /** 53: ** splitline ( parse a line into an array of strings ) 54: **/ 55: #define is_delim(x) ((x)==' '||(x)=='/t') 56: 57: char ** splitline(char *line) 58: /* 59: * purpose: split a line into array of white-space separated tokens 60: * returns: a NULL-terminated array of pointers to copies of the tokens 61: * or NULL if line if no tokens on the line 62: * action: traverse the array, locate strings, make copies 63: * note: strtok() could work, but we may want to add quotes later 64: */ 65: { 66: char *newstr(); 67: char **args ; 68: int spots = 0; /* spots in table */ 69: int bufspace = 0; /* bytes in table */ 70: int argnum = 0; /* slots used */ 71: char *cp = line; /* pos in string */ 72: char *start; 73: int len; 74: 75: if ( line == NULL ) /* handle special case */ 76: return NULL; 77: 78: args = emalloc(BUFSIZ); /* initialize array */ 79: bufspace = BUFSIZ; 80: spots = BUFSIZ/sizeof(char *); 81: 82: while( *cp != '/0' ) 83: { 84: while ( is_delim(*cp) ) /* skip leading spaces */ 85: cp++; 86: if ( *cp == '/0' ) /* quit at end-o-string */ 87: break; 88: 89: /* make sure the array has room (+1 for NULL) */ 90: if ( argnum+1 >= spots ){ 91: args = erealloc(args,bufspace+BUFSIZ); 92: bufspace += BUFSIZ; 93: spots += (BUFSIZ/sizeof(char *)); 94: } 95: 96: /* mark start, then find end of word */ 97: start = cp; 98: len = 1; 99: while (*++cp != '/0' && !(is_delim(*cp)) ) 100: len++; 101: args[argnum++] = newstr(start, len); 102: } 103: args[argnum] = NULL; 104: return args; 105: } 106: 107: /* 108: * purpose: constructor for strings 109: * returns: a string, never NULL 110: */ 111: char *newstr(char *s, int l) 112: { 113: char *rv = emalloc(l+1); 114: 115: rv[l] = '/0'; 116: strncpy(rv, s, l); 117: return rv; 118: } 119: 120: void 121: freelist(char **list) 122: /* 123: * purpose: free the list returned by splitline 124: * returns: nothing 125: * action: free all strings in list and then free the list 126: */ 127: { 128: char **cp = list; 129: while( *cp ) 130: free(*cp++); 131: free(list); 132: } 133: 134: void * emalloc(size_t n) 135: { 136: void *rv ; 137: if ( (rv = malloc(n)) == NULL ) 138: fatal("out of memory","",1); 139: return rv; 140: } 141: void * erealloc(void *p, size_t n) 142: { 143: void *rv; 144: if ( (rv = realloc(p,n)) == NULL ) 145: fatal("realloc() failed","",1); 146: return rv; 147: } 148: 149: