要求:job5增加文件重定向功能
思路
- 1:分割字符串,提取信息
- 2:在子进程中利用
dup2
命令按需要将标准输入输出重定向为指定的输入输出来源
代码
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
char op[100],t[100],p[100],r[100],q[100];
int st[10];
char *argv[10]; //把命令按空格划分
int argc=0; //命令以空格分割后个单词个数
char *input; //输入地址,若无重定向,默认为NULL,若重定向了,则为重定向地址
char *output;//输出的地址,若无重定向,默认为NULL,若重定向了,则为重定向的地址
int mode=0; //如果重定向了输出,mode为0表示覆盖输出,为1表示追加输出
void parse_command(char *command)
{ //把输入的命令串处理“分割”,提取有用信息
//init
memset(st,0,sizeof(st));
mode=0;
input=NULL;
output=NULL;
//分割字符串
char *ptr;
int i=0;
ptr=NULL;
ptr=strtok(command," ");
while(ptr)
{
argv[i]=ptr;
++i;
ptr=strtok(NULL," ");
}
argv[i]=NULL;
argc=i;
//遍历所有单词,查找重定向
for(int i=1;i<argc;i++)
{
strcpy(op,argv[i]);
if(op[0]=='<') //重定向输入
{ //提取地址
int k=0;
for(int j=1;op[j]!='\0';j++)
r[k++]=op[j];
r[k]='\0';
if(r[0]!='/')
{
getcwd(q,sizeof(q));
strcat(q,"/");
strcat(q,r);
input=q;
}
else
input=r;
st[i]=1; //标记一下,后面要在命令串中把这个筛掉
}
else if(op[0]=='>') //重定向输出
{ //提取地址
int k=0;
for(int j=1;op[j]!='\0';j++)
{
if(op[j]=='>') continue;
t[k++]=op[j];
}
t[k]='\0';
if(t[0]!='/')
{
getcwd(p,sizeof(p));
strcat(p,"/");
strcat(p,t);
output=p;
}
else
output=t;
if(op[1]=='>')
mode=1;
st[i]=1;//标记一下,后面要在命令串中把这个筛掉
}
}
//在分割后的命令串中把重定向了的部分筛掉,因为他们不能再往下传了
char *tmp[10];
int k=0;
for(int i=0;i<argc;i++)
{
if(!st[i])
tmp[k++]=argv[i];
}
for(int i=0;i<k;i++) //更新argc和argv
argv[i]=tmp[i];
argv[k]=NULL;
argc=k;
}
void dump_command() //输出字符串信息的,检验分割提取操作进行的是否正确
{
printf("%d\n",argc);
for(int i=0;i<argc;i++)
printf("%s ",argv[i]);
printf("\n");
if(input!=NULL)
printf("input:%s\n",input);
else
printf("input:NULL\n");
if(output!=NULL)
printf("output:%s mode:%d\n",output,mode);
else
printf("output:NULL\n");
}
void redirect() //利用dup2进行重定向操作
{
int fd1,fd2;
if(input!=NULL)
{
fd1=open(input,O_RDONLY);
if(fd1==-1)
{
printf("input fail open!\n");
exit(0);
}
dup2(fd1,0);
}
if(output!=NULL)
{
if(mode==0)
fd2=open(output,O_CREAT|O_TRUNC|O_WRONLY,0666);
else
fd2=open(output,O_CREAT|O_APPEND|O_WRONLY,0666);
if(fd2==-1)
{
printf("output fail open\n");
exit(0);
}
dup2(fd2,1);
}
}
void mysys(char *command)
{
parse_command(command);
if(strcmp(argv[0],"cd")==0)
chdir(argv[1]);
else if(strcmp(argv[0],"exit")==0)
exit(0);
else if(strcmp(argv[0],"pwd")==0)
{
char path[255];
getcwd(path,sizeof(path));
puts(path);
}
else
{
pid_t pid;
pid=fork();
if(pid==0)
{
redirect(); //注意,这里要在子进程中重定向
int error=execvp(argv[0],argv);
if(error<0)
{
perror("execv");
}
}
wait(NULL);
}
}
int main()
{
char str[100];
while(1)
{
printf(">");
gets(str);
mysys(str);
}
return 0;
}
注意点
- 这里的文件重定向操作是在子进程里完成,而不是在主进程里完成
如果是在主进程里进行操作,会影响主进程的后续操作。 - 可以写一个
parse_command
函数,统一把字符串处理到位,把需要的信息都给处理出来,然后再写一个统一的输出函数dump_command()
进行检验,把需要的信息可以开成全局变量,这样不用作为函数的参数传来传去,从全局的角度来看,更加直观,不易出错。 - 这里遍历命令单词串,查找带重定向符的单词时,最好要用不同的char型数组、指针,这样可以避免在循环中的先后操作而产生的覆盖问题,比如查找
<
操作符时,用了r
和q
,而查找>
操作符时,用了t
和p
- 打开文件的时候,要注意选用的参数
打开一个想要读的文件:fd1=open(input,O_RDONLY);
打开一个想要覆盖写的文件:fd2=open(output,O_CREAT|O_TRUNC|O_WRONLY,0666);
打开一个想要追加写的文件:fd2=open(output,O_CREAT|O_APPEND|O_WRONLY,0666);
- 对
echo
命令而言,重定向输入符<
是没有意义的,所以不需要考虑
2022/4.3更新
强化了程序的模块化,增强了代码的可读性
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
//这里的全局变量暂时还消不掉,因为如果用的是局部变量,那么在调用完返回的时候就被销毁了,但是其实是不能销毁的
char op[100];
char t[100],p[100],r[100],q[100];
struct command {
int argc;
char *argv[10];
char *input;
char *output;
int mode;
};
int split(char *line, char *separator, char *word_array[])
{
int word_count=0;
char *word=NULL;
word=strtok(line,separator);
while(word)
{
word_array[word_count]=word;
word_count++;
word=strtok(NULL,separator);
}
word_array[word_count]=NULL;
return word_count;
}
void parse_command(char *command,struct command *order)
{
//define&init
int st[10];
memset(st,0,sizeof(st));
order->mode=0;
order->input=NULL;
order->output=NULL;
//split
char *argv[10];
int argc=split(command," ",argv);
//test
/*for(int i=0;i<argc;i++)
{
printf("%s ",argv[i]);
fflush(stdout);
}
printf("\n");*/
//search < > >>
for(int i=1;i<argc;i++)
{
strcpy(op,argv[i]);
//printf("[%s]\n",op);
//fflush(stdout);
if(op[0]=='<')
{
int k=0;
for(int j=1;op[j]!='\0';j++)
r[k++]=op[j];
r[k]='\0';
if(r[0]!='/')
{
getcwd(q,sizeof(q));
strcat(q,"/");
strcat(q,r);
order->input=q;
}
else
order->input=r;
st[i]=1;
//printf("1:%s\n",input);
}
else if(op[0]=='>')
{
int k=0;
for(int j=1;op[j]!='\0';j++)
{
if(op[j]=='>') continue;
t[k++]=op[j];
}
t[k]='\0';
//printf("[%s]\n",t);
//fflush(stdout);
if(t[0]!='/')
{
getcwd(p,sizeof(p));
//printf("[%s]\n",p);
//fflush(stdout);
strcat(p,"/");
strcat(p,t);
//printf("[%s]\n",p);
//fflush(stdout);
order->output=p;
//printf("-1\n");
//fflush(stdout);
}
else
order->output=t;
if(op[1]=='>')
order->mode=1;
//printf("[%s]\n",output);
//fflush(stdout);
st[i]=1;
}
}
int k=0;
for(int i=0;i<argc;i++)
{
if(!st[i])
order->argv[k++]=argv[i];
}
order->argv[k]=NULL;
order->argc=k;
//printf("k:%d\n",k);
//printf("2:%s\n",input);*/
}
void dump_command(struct command *order)
{
printf("%d\n",order->argc);
for(int i=0;i<order->argc;i++)
printf("%s ",order->argv[i]);
printf("\n");
//printf("-1\n");
//fflush(stdout);
if(order->input!=NULL)
printf("input:%s\n",order->input);
else
printf("input:NULL\n");
//printf("0\n");
//fflush(stdout);
if(order->output!=NULL)
printf("output:%s mode:%d\n",order->output,order->mode);
else
printf("output:NULL\n");
}
void redirect(struct command *order)
{
int fd1,fd2;
if(order->input!=NULL)
{
fd1=open(order->input,O_RDONLY);
if(fd1==-1)
{
printf("input fail open!\n");
exit(0);
}
dup2(fd1,0);
}
if(order->output!=NULL)
{
//printf("%s\n",output);
if(order->mode==0)
fd2=open(order->output,O_CREAT|O_TRUNC|O_WRONLY,0666);
else
fd2=open(order->output,O_CREAT|O_APPEND|O_WRONLY,0666);
if(fd2==-1)
{
printf("output fail open\n");
exit(0);
}
dup2(fd2,1);
}
}
void mysys(char *command)
{
struct command order;
parse_command(command, &order);
//dump_command(&order);
if(strcmp(order.argv[0],"cd")==0)
chdir(order.argv[1]);
else if(strcmp(order.argv[0],"exit")==0)
exit(0);
else if(strcmp(order.argv[0],"pwd")==0)
{
char path[255];
getcwd(path,sizeof(path));
puts(path);
}
else
{
pid_t pid;
pid=fork();
if(pid==0)
{
redirect(&order); //redirect
int error=execvp(order.argv[0],order.argv);
if(error<0)
perror("execv");
}
wait(NULL);
}
}
int main()
{
char str[100];
while(1)
{
printf(">");
gets(str);
mysys(str);
}
return 0;
}
版权声明:本文为weixin_45798993原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。