Tiny-shell (二)

Tiny-shell(二): 简单实现重定向


概述

上一讲我们实现了一个极简的shell,可以执行用户输入的简单命令,这一讲我们实现shell中的重定向。

在计算机领域,重定向是大多数命令行解释器所具有的功能,包括各种可以将标准流重定向用户规定地点的Unix shells。类Unix操作系统的程序可以透过dup2(2)系统调用完成重定向,或者透过缺少一些灵活性但是更高一级层次的freopen(3)和popen(3)来完成。(来自Wikipedia)
体现在shell中: cat < source > destination,需要重定向输出到destination,把输入重定向到source。

思路

我们简单的实现一下重定向,按照先处理输出,再处理输入的顺序来,也就是先处理>再处理<。因为上一讲我们创建了一个缓冲区(参数数组),所以我们在缓冲区对命令进行处理,先取出>符号后面的参数,然后从>截断字符串,这时候字符串就变成了cat < source,然后处理<,再截断字符串变成cat,最后执行命令即可。

函数说明

这里我们要额外增加两个函数parse_redirect_inparse_redirect_out来处理重定向。同时,借用opendup2函数来进行重定向。(关于opendup2请看这里这里)。open能打开文件并返回一个文件描述符,然后用dup2来进行重定向。

运行

编译:gcc -o tsh1 tsh1.c execute_cmd_redirect.c parse_redirect.c make_argv.c

tsh1>> cat f1
123
tsh1>> cat f2
cat: f2: No such file or directory
tsh1>> cat < f1 > f2
tsh1>> cat f2
123

注意运行时按cat < f1 > f2即可,重定向输出放后面

源代码

parse_redirect.c

/**
 * @Filename: parse_redirect.c
 * @Description: 处理输入输出的重定向,按特定顺序调用,为了直观,忽略了错误检查。
 */
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#define FFLAG (O_WRONLY | O_CREAT | O_TRUNC)
#define FMODE (S_IRUSR | S_IWUSR)

int parse_redirect_in(char *cmd) {    /* 遇到'<'重定向输入 */
   int infd;
   char *infile;

   infile = strchr(cmd, '<');
   if (infile == NULL)   /* 不用处理即返回 */
       return 0;
   *infile = 0;                  /* 把'<'后面的字符串都去掉,因为处理了 */
   infile = strtok(infile + 1, " \t");
   infd = open(infile, O_RDONLY);
   dup2(infd, STDIN_FILENO);
   return close(infd);
}

int parse_redirect_out(char *cmd) {  /* 遇到'>'重定输出 */
   int outfd;
   char *outfile;

   outfile = strchr(cmd, '>');
   if (outfile == NULL)     /* 不用处理即返回 */
       return 0;
   *outfile = 0;                  /* 将'>'后面的字符串都去掉,因为处理了 */
   outfile = strtok(outfile + 1, " \t");  
   outfd = open(outfile, FFLAG, FMODE);
   dup2(outfd, STDOUT_FILENO);
   return close(outfd);
} 

execute_cmd_redirect.c

/**
 * @Filename: execute_cmd_redirect.c
 * @Description: 处理出入输出的重定向,为了直观,省去了错误检查
 */
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int make_argv(const char *s, const char *delimiters, char ***argvp);
int parse_redirect_in(char *s);
int parse_redirect_out(char *s);

void execute_cmd(char *incmd) {
   char **chargv;
   parse_redirect_out(incmd);   /* 先处理输出重定向 */ 
   parse_redirect_in(incmd);  /* 处理输入重定向 */ 
   make_argv(incmd, " \t", &chargv);
   execvp(chargv[0], chargv);
   
   exit(1);
}

tsh1.c

此文件地址

posted @ 2020-03-01 22:18  chrisynl  阅读(317)  评论(0编辑  收藏  举报