一、作业 myecho.c
实现系统程序 echo 相同的功能
能通过如下测试
$ ./myecho abc abc $ ./myecho abc xyz abc xyz $ ./myecho abc >log.txt $ cat log.txt abc
代码如下:
#include <stdlib.h>
#include <stdio.h>
int main(int agrc,char *agrv[]){
int i;
for(i=1;i<agrc;i++){
printf("%s",agrv[i]);
}
printf("\n");
return 0;
}
二、作业 mycat2.c
实现系统程序 cat 相同的功能
能通过如下测试
# 创建一个测试文件 log.txt,内容为 hello $ echo hello >log.txt # 显示 log.txt 的内容 $ ./mycat log.txt hello # 将 mycat 的标准输入定向到文件 log.txt $ ./mycat <log.txt hello # 将 mycat 的标准输出定向到文件 out.txt $ ./mycat >log.txt world ctrl-D 结束输入
老师ppt上的代码,直接照着敲就行:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include<sys/stat.h>
void copy(int src_fd,int dst_fd)
{
char buf[512];
int count;
while(count = read(src_fd,buf,512))
write(dst_fd, buf, count);
}
int main(int argc,char *argv[])
{
int fd;
if(argc==1)
fd = 0;
else{
fd = open(argv[1],O_RDONLY);
}
copy(fd,1);
}
三、作业 sh2.c
实现shell程序,要求在第1版的基础上,增加文件重定向功能
重定向输入
重定向输出
重定向追加
思路:
- 输入重定向:指的是重新指定设备来代替键盘作为新的输入设备;
- 输出重定向:指的是重新指定设备来代替显示器作为新的输出设备
< 输入
> 覆盖输出
>> 追加输出
老师给的提示:
while (1) {
char *argv[];
int argc;
char *output;
char *input;
gets(line);
parse line; //分词实现
// line = "echo abc >log.txt";
// argv = {"echo", "abc", NULL};
// argc = 2;
// output = "log.txt"
pid = fork();
if (pid == 0) {
redirect stdout to log.txt; //重定向实现
execvp(argv[0], argv);
}
wait();
}
个人觉得难度在于分词和检验'<','>','>>'的操作,c基础不好的很容易出现各种各样的问题。分词处理好后,就是把之前写的mysys函数直接套用加上改一下输入输出重定向就行了。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
//定义全局变量,建议还是用个结构体保存比较好
char *argv[20]; //命令或地址
int argc; //命令或地址数
char *output; //输出文件名
char *input; //输入文件名
int append; //追加模式,1:追加 0:覆盖
void parse(char *command)
{ //按空格“ ”进行分词 并将其保存在argv[]中
//如“echo ab >log.txt" 分词后agrc=3,agrv[]={"echo","ab",">log.txt"}
char *line=(char *)malloc(sizeof*(command));
strcpy(line,command);
char *word;
word=strtok(line," ");
while(word!=NULL)
{
argv[argc++]=word;
word=strtok(NULL," ");
}
}
void parse_test(char *s){ //将argv最后一个字串进行“<”,“>>”,“>”检验
//如agrc=3 agrv[]={"echo","ab",">log.txt"} output=NULL则s=">log.txt"
//检验后 agrc=2 agrv[]={"echo","ab"} output="log.txt"
if(s[0]=='<'){ //s代表argv最后一个字符">log.txt"
input=&s[1];
argc--; //
argv[argc]=NULL;
}
else if(s[0]=='>'&&s[1]=='>'){
output=&s[2];
append=1;
argc--;
argv[argc]=NULL;
}
else if(s[0]=='>'){
output=&s[1];
argc--;
argv[argc]=NULL;
}
}
void child(){ //子进程
int fd;
if(input!=NULL){
fd=open(input,O_RDONLY,0666);
dup2(fd,0); //重定向 0号描述符指向了fd描述符所指位置
close(fd);
}
if(output!=NULL&&append==0){
fd=open(output,O_RDWR|O_CREAT,0666);
dup2(fd,1);
close(fd);
}
if(append!=0){
fd=open(output,O_RDWR|O_APPEND|O_CREAT,0777);
dup2(fd,1);
close(fd);
}
execvp(argv[0],argv);
}
int main(){
while(1){
printf(">");
char line[20];
fgets(line,20,stdin); //如之前所说,建议用fgets读
line[strlen(line)-1]=0; //把line最后的回车变成“/0”
//全局变量初始化
argc=0;
for(int i=0;i<20;i++)
argv[i]=NULL;
input=NULL;
output=NULL;
append=0;
parse(line);
parse_test(argv[argc-1]);
//下面就相当之前写的mysys.c部分
if(!strcmp(argv[0],"cd")){
chdir(argv[1]);
}
else if(!strcmp(argv[0],"exit")){
exit(1);
}
else{
int pid=fork();
if(pid==0){
child();
}
}
wait(NULL);
}
}