实验3.3 Shell编程实验(进程管理实验)
1、实验目的
通过编写shell程序,了解子进程的创建和父进程与子进程间的协同,获得多进程程序的编程经验。
2、实验内容1
设计一个简单的shell解释程序,能实现基本的bsh功能。
3、实验原理
将每一条命令分子段压入argv栈。然后再子进程中调用execvp()来实现该命令的功能。
4、代码(源代码清单)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFERSIZE 256
//最简单的shell,只是简单的执行命令调用,没有任何的其他功能
int main()
{
char buf[BUFFERSIZE],*cmd,*argv[100];
char inchar;
int n,sv,buflength;
int result;
buflength = 0;
for(;;) {
printf("=> ");
//处理过长的命令;
inchar = getchar();//读取命令
while (inchar != '\n' && buflength < BUFFERSIZE ){
buf[buflength++] = inchar;
inchar = getchar();
}
if (buflength > BUFFERSIZE){
printf("Command too long,please enter again!\n");
buflength = 0;
continue;
}
else
buf[buflength] = '\0';
//解析命令行,分成一个个的标记
//char *strtok(char *s,char *delim)
//分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。
cmd=strtok(buf," \t\n");
if(cmd) {
if(strcmp(cmd,"exit")==0) exit(0);
n=0;
argv[n++]=cmd;
while(argv[n++]=strtok(NULL," \t\n"));
if(fork()==0) {
execvp(cmd,argv);
fprintf(stderr,"sxh:%s:command not found.\n",buf);//如果子进程顺利执行,这段话是不会执行的
exit(1);
}
wait(&sv);
buflength = 0;
}
}
}
实验内容2
编写一个带有重定向和管道功能的Shell
1.设计思路
通过fork()创建子进程,用execvp()更改子进程代码,用wait()等待子进程结束。这三个系统调用可以很好地创建多进程。另一方面,编写的Shell要实现管道功能,需要用pipe()创建管道使子进程进行通信。
2.源代码清单
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#define BUFFERSIZE256
//具有输入输出重定向的功能 和管道功能
int
main()
{
char buf[256],*buf2,*cmd,*cmd2,*argv[64],*argv2[64],*infile,*outfile;
char inchar;
int n,sv,buflength,fd[2];
for(;;) {
buflength = 0;
printf("=> ");
inchar = getchar();
while (inchar != '\n' && buflength < BUFFERSIZE ){
buf[buflength++] = inchar;
inchar = getchar();
}
if (buflength > BUFFERSIZE){
fprintf(stderr,"Command too long,please enter again!\n");
buflength = 0;
continue;
}
else
buf[buflength] = '\0';
//检查是否具有管道操作符
//strstr()在字符串中查找指定字符串的第一次出现,buf2指向管道符号前端的命令
buf2=strstr(buf,"|");
if(buf2)
*buf2++='\0';
else {
//否则查看是否具有重定向的操作符
infile=strstr(buf,"<");
outfile=strstr(buf,">");
if(infile) {
*infile='\0';
infile=strtok(infile+1," \t\n");
}
if(outfile) {
*outfile='\0';
outfile=strtok(outfile+1," \t\n");
}
}
//解析命令行,分成一个个的标记
cmd=strtok(buf," \t\n");
//执行管道命令
if(buf2){
if(strcmp(cmd,"exit")==0) exit(0);
if(!cmd) {
fprintf(stderr,"Command token error.\n");
exit(1);
}
n=0;
//管道后端的命令
argv[n++]=cmd;
while(argv[n++]=strtok(NULL," \t\n"));
//管道前端的命令
cmd2=strtok(buf2," \t\n");
if(!cmd2) {
fprintf(stderr,"Command token error.\n");
exit(1);
}
n=0;
argv2[n++]=cmd2;
while(argv2[n++]=strtok(NULL," \t\n"));
pipe(fd);
if(fork()==0) {
dup2(fd[0],0); //dup2 复制文件句柄,将fd[0]复制到描述符0。
close(fd[0]); close(fd[1]);
execvp(cmd2,argv2);
fprintf(stderr,"** bad command\n"); exit(1);
} else if(fork()==0) {
dup2(fd[1],1);
close(fd[0]);close(fd[1]);
execvp(cmd,argv);
fprintf(stderr,"** bad command\n"); exit(1);
}
close(fd[0]);
close(fd[1]);
wait(&sv);
wait(&sv);
buflength = 0;
}
//如果没有管道命令,如果有重定向就执行重定向操作,如果没有重定向就当作普通shell命令执行
else{
if(cmd) {
if(strcmp(cmd,"exit")==0) exit(0);
n=0;
argv[n++]=cmd;
while(argv[n++]=strtok(NULL," \t\n"));
if(fork()==0) {
int fd0=-1,fd1=-1;
if(infile) fd0=open(infile,O_RDONLY);
if(outfile) fd1=open(outfile,O_CREAT|O_WRONLY,0666);
if(fd0!=-1) dup2(fd0,0);//dup2 复制文件句柄,将fd0复制到描述符0。
if(fd1!=-1) dup2(fd1,1);//dup2 复制文件句柄,将fd1复制到描述符1。
close(fd0);
close(fd1);
execvp(cmd,argv);
fprintf(stderr,"** Bad command\n");
exit(1);
}
wait(&sv);
buflength = 0;
}
}
}//for
}