参考代码:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h> // Simplifed xv6 shell. #define MAXARGS 10 // All commands have at least a type. Have looked at the type, the code
// typically casts the *cmd to some specific cmd type.
struct cmd {
int type; // ' ' (exec), | (pipe), '<' or '>' for redirection
}; struct execcmd {//普通指令
int type; // ' '
char *argv[MAXARGS]; // arguments to the command to be exec-ed
}; struct redircmd {//重定向
int type; // < or >
struct cmd *cmd; // the command to be run (e.g., an execcmd)
char *file; // the input/output file
int mode; // the mode to open the file with
int fd; // the file descriptor number to use for the file
}; struct pipecmd {//pipe指令
int type; // |
struct cmd *left; // left side of pipe
struct cmd *right; // right side of pipe
}; int fork1(void); // Fork but exits on failure.
struct cmd *parsecmd(char*); // Execute cmd. Never returns.
void
runcmd(struct cmd *cmd)
{
int p[], r;
struct execcmd *ecmd;
struct pipecmd *pcmd;
struct redircmd *rcmd; if(cmd == )
exit(); switch(cmd->type){
default:
fprintf(stderr, "unknown runcmd\n");
exit(-); case ' ':
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[] == ){
fprintf(stderr, "exec not implemented\n");
exit();
}
execvp(ecmd->argv[], ecmd->argv);
// Your code here ...
break;
case '>':
case '<':
rcmd = (struct redircmd*)cmd;
// Your code here ...
close(rcmd->fd);
if(open(rcmd->file, rcmd->mode) < )
{
fprintf(stderr, "redir not implemented\n");
exit();
}
runcmd(rcmd->cmd);
break; case '|':
pcmd = (struct pipecmd*)cmd;
//fprintf(stderr, "pipe not implemented\n");
// Your code here ...
if(pipe(p) < )
{
fprintf(stderr, "pipe not implemented\n");
exit();
} if(fork1() == )
{
close();
dup2(p[],);
close(p[]);
runcmd(pcmd->left);
} if(fork1() == )
{
close();
dup2(p[],);
close(p[]);
runcmd(pcmd->right);
} close(p[]);
close(p[]);
wait();
wait();
break; }
exit();
} int
getcmd(char *buf, int nbuf)// 检测输入是否是标准输入流stdin,然后把用户输入存到buffer里
{ if (isatty(fileno(stdin)))//fileno()函数 功能:把文件流指针转换成文件描述符;
//isatty(判断文件描述词是否是为终端机)若为终端设备则返回1(真),否则返回0(假)
fprintf(stdout, "$ ");//库函数 int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中。
memset(buf, , nbuf);
fgets(buf, nbuf, stdin);//C 库函数 char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行,
//并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
if(buf[] == ) // EOF
return -;
return ;
} int
main(void)
{
static char buf[];
int fd, r; // Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= ){
if(buf[] == 'c' && buf[] == 'd' && buf[] == ' '){
// Clumsy but will have to do for now.
// Chdir has no effect on the parent if run in the child.
buf[strlen(buf)-] = ; // chop \n
if(chdir(buf+) < )
fprintf(stderr, "cannot cd %s\n", buf+);
continue;
}
if(fork1() == )
runcmd(parsecmd(buf));
wait(&r);
}
exit();
} int
fork1(void)
{
int pid; pid = fork();
if(pid == -)
perror("fork");
return pid;
} struct cmd*
execcmd(void)// 为一个cmd数据结构分配内存
{
struct execcmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = ' ';
return (struct cmd*)cmd;
} struct cmd*
redircmd(struct cmd *subcmd, char *file, int type)
{
struct redircmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = type;
cmd->cmd = subcmd;
cmd->file = file;
cmd->mode = (type == '<') ? O_RDONLY : O_WRONLY|O_CREAT|O_TRUNC;
cmd->fd = (type == '<') ? : ;
return (struct cmd*)cmd;
} struct cmd*
pipecmd(struct cmd *left, struct cmd *right)
{
struct pipecmd *cmd; cmd = malloc(sizeof(*cmd));
memset(cmd, , sizeof(*cmd));
cmd->type = '|';
cmd->left = left;
cmd->right = right;
return (struct cmd*)cmd;
} // Parsing char whitespace[] = " \t\r\n\v";
char symbols[] = "<|>"; int
gettoken(char **ps, char *es, char **q, char **eq) // 把地址ps到es的字符串中的变量找到,并存到q到eq的地址去
{
char *s;
int ret; s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
if(q)
*q = s;
ret = *s;
switch(*s){
case :
break;
case '|':
case '<':
s++;
break;
case '>':
s++;
break;
default:
ret = 'a';
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
s++;
break;
}
if(eq)
*eq = s; while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return ret;
} int
peek(char **ps, char *es, char *toks)//判断从地址ps到es的字符串是否含有toks里面的字符
{
char *s; s = *ps;
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return *s && strchr(toks, *s);
} struct cmd *parseline(char**, char*);
struct cmd *parsepipe(char**, char*);
struct cmd *parseexec(char**, char*); // make a copy of the characters in the input buffer, starting from s through es.
// null-terminate the copy to make it a string.
char
*mkcopy(char *s, char *es) // s指向需要拷贝的字符串头,es指向需要拷贝的字符串结尾. 这个函数拷贝从s到es的字符串,然后返回拷贝的地址。
{
int n = es - s;
char *c = malloc(n+);
assert(c);
strncpy(c, s, n);
c[n] = ;
return c;
} struct cmd*
parsecmd(char *s)// 解析命令把buffer里的命令包装成可执行的数据结构struct cmd
{
char *es;
struct cmd *cmd; es = s + strlen(s);
cmd = parseline(&s, es);
peek(&s, es, "");
if(s != es){
fprintf(stderr, "leftovers: %s\n", s);
exit(-);
}
return cmd;
} struct cmd*
parseline(char **ps, char *es)
{
struct cmd *cmd;
cmd = parsepipe(ps, es);
return cmd;
} struct cmd*
parsepipe(char **ps, char *es)
{
struct cmd *cmd; cmd = parseexec(ps, es);
if(peek(ps, es, "|")){
gettoken(ps, es, , );
cmd = pipecmd(cmd, parsepipe(ps, es));
}
return cmd;
} struct cmd*
parseredirs(struct cmd *cmd, char **ps, char *es)
{
int tok;
char *q, *eq; while(peek(ps, es, "<>")){
tok = gettoken(ps, es, , );
if(gettoken(ps, es, &q, &eq) != 'a') {
fprintf(stderr, "missing file for redirection\n");
exit(-);
}
switch(tok){
case '<':
cmd = redircmd(cmd, mkcopy(q, eq), '<');
break;
case '>':
cmd = redircmd(cmd, mkcopy(q, eq), '>');
break;
}
}
return cmd;
} struct cmd*
parseexec(char **ps, char *es)
{
char *q, *eq;
int tok, argc;
struct execcmd *cmd;
struct cmd *ret; ret = execcmd();
cmd = (struct execcmd*)ret; argc = ;
ret = parseredirs(ret, ps, es);
while(!peek(ps, es, "|")){
if((tok=gettoken(ps, es, &q, &eq)) == )
break;
if(tok != 'a') {
fprintf(stderr, "syntax error\n");
exit(-);
}
cmd->argv[argc] = mkcopy(q, eq);
argc++;
if(argc >= MAXARGS) {
fprintf(stderr, "too many args\n");
exit(-);
}
ret = parseredirs(ret, ps, es);
}
cmd->argv[argc] = ;
return ret;
}

最新文章

  1. 排序算法总结第二弹----冒泡排序---javascript描述
  2. apk 破解
  3. sublime 3
  4. [转]SQLServer2008日志文件无法收缩处理方法
  5. 边工作边刷题:70天一遍leetcode: day 88
  6. photoshop 常用快捷键大全
  7. 如何将linux用在开发环境中的
  8. 《JS权威指南学习总结--7.9 ES5中的数组方法》
  9. Editplus配置java运行环境以及其他需求的简单设置
  10. Slave_SQL_Runing:NO 复制出现问题的解决办法
  11. 201521123009 《Java程序设计》第7周学习总结
  12. 如何更改Ubuntu的root密码
  13. Android 开发之Windows环境下Android Studio安装和使用教程
  14. 背景图片固定不随页面上下滚动而滚动 ,属性 background-attachment
  15. 为SNP增加种族人群频率
  16. npm安装cnpm报错
  17. DOM中offsetLeft与style.left的区别
  18. CentOS 65 java 访问 MS SQL
  19. 负载均衡之-LVS
  20. Netty原理剖析

热门文章

  1. Python的一些高级特性
  2. 配置adb环境与简单命令
  3. php的优势与缺点
  4. postman+xmysql实现postman与数据库的交互,获取数据库的值来作为参数进行请求
  5. TP 验证码
  6. JDK动态代理和CGLIB动态代理编码
  7. unity ui坐标系转换
  8. Oracle 存储过程--01
  9. nodeJs express4 框架
  10. Sass--传一个不带值的参数