结果展示
可以实现>,>>,<重定向,pwd,cd,exit操作
有一定的健壮性比如:可以识别">log"和"> log"
目录
job5/sh2.c
实现shell程序,要求在第1版的基础上,增加文件重定向功能
- 重定向输入
- 重定向输出
- 重定向追加
指路job3:实现了基础的sh1.c
操作系统实践 job3_LarsGyonX的博客-CSDN博客
然后来康康job5吧!老师在课上给了一个伪代码:
首先分割出每一行命令,实现内置命令:exit,pwd,cd,然后创建子进程,实现systerm以及重定向功能。
个人在老师的思路上进行了补充和完善。
main()
首先是主函数:分割每一行字符串,并将该行命令传给mysh2.
int main()
{
while(1)
{
char command[100]={0};
char c;
printf(">");
int i=0;
do{
c=getchar();
command[i]=c;
i++;
}while(c!='\n');
command[i-1]=0;
mysh2(command);
}
}
mysh2()
分别实现内置功能exit/pwd/cd,然后创建子进程,进入子函数实现systerm功能。这边不理解的看job3博客。
void mysh2(char command[])
{
//printf("command is %s in mysh2\n",command);
if(!strcmp(command,"exit"))exit(0);
else if(!strcmp(command,"pwd"))
{
char *path=getcwd(NULL,0);
printf("Current directory:%s\n",path);
free(path);
}
else if(command[0]=='c'&&command[1]=='d')
{
char cd[100]={0};
strcpy(cd,command+3);
int error=chdir(cd);
if(error<0)perror("cd");
else{
char *path=getcwd(NULL,0);
printf("Current directory:%s\n",path);
free(path);
}
}
else
{
pid_t pid;
pid=fork();
if(pid==0)
{
child(command);
}
wait(NULL);
}
}
child()
略长,但是思路挺简单的,进一步分割command,检测到>,<,>>就将文件名开始的下标传给redirect重定向函数,(>是0,<是1,>>是2)处理完了以后,将文件名后的下标再传回child函数。
举个例子:cat <log >log1,检测到<是i=4,将其传给redirect提取log的文件名,返回i=7也就是'g'处的下标,进行下一轮检索。
为保证健壮性,讨论了很多可能性,代码较长,但是逻辑非常简单。
注意:先处理重定向,再调用execl,因为得先close(fd)重定向功能才会起作用。
void child(char command[]){
//printf("command is %s in child\n",command);
if(command==NULL){
printf("Error: wrong command!");
exit(0);
}
else{
// printf("can it been sent here %s\n",command);
for(int i =0;command[i]!='\0';i++)
{
//>log
if(command[i]=='>'&&command[i+1]!=' '&&command[i+1]!='>')
{
i=redirect(i+1,command,0);
}
//> log
else if(command[i]=='>'&&command[i+1]==' ')
{
i=redirect(i+2,command,0);
}
//<log
else if(command[i]=='<'&&command[i+1]!=' ')
{
i=redirect(i+1,command,1);
}
//< log
else if(command[i]=='<'&&command[i+1]==' ')
{
i=redirect(i+2,command,1);
}
//>>log
else if(command[i]=='>'&&command[i+1]=='>'&&command[i+1]!=' ')
{
i=redirect(i+2,command,2);
}
//>> log
else if(command[i]=='>'&&command[i+1]=='>'&&command[i+2]==' ')
{
i=redirect(i+3,command,2);
}
}
int error=execl("/bin/sh","sh","-c",command,NULL);
if(error<0)perror("execl");
}
}
redirect()
重定向函数!
知识点
先回顾一下重点知识
#include <unistd.h>
int dup2(int oldfd, int newfd);
通过复制文件描述符oldfd,创建一个新的文件描述符newfd
newfd和oldfd指向相同的文件
dup2(fd,1);即为下图所示,将标准输出指向文件log,也就是说可以通过标准输出将内容输入或追加到log中。
->close(fd)->
同理dup2(fd,0)就是通过标准输入将log中的内容提取出来。
思路
- 首先将文件路径/文件名提取出来
- 创建/打开文件,注意打开参数的区别!
- 如果是<就是重定向输入
- 如果是>就是重定向输出
- 如果是>>就是重定向添加
最后关闭文件
int redirect(int i,char command[],int flag)
{
//printf("command is %s in redirect,i=%d\n",command,i);
char file[100];
int k=0,j,fd;
for(j=i;command[j]!=' '&&command[j]!='\0';j++)
{
file[k++]=command[j];
}
file[k]=0;
//printf("filename is %s\n",file);
if(flag==0)
{
fd=open(file,O_CREAT|O_RDWR,0666);
dup2(fd,1);
}
else if(flag==1)
{
fd=open(file,O_CREAT|O_RDWR,0666);
dup2(fd,0);
}
else if(flag==2)
{
fd=open(file,O_CREAT|O_APPEND,0666);
dup2(fd,1);
}
close(fd);
return j-1;
}
job1-job5的代码都传在gitee上了,欢迎交流指正~~~~