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_in
和parse_redirect_out
来处理重定向。同时,借用open
和dup2
函数来进行重定向。(关于open
和dup2
请看这里和这里)。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);
}