c语言实现简单的shell
记录一下上课讲的实现简单的shell(含有单个管道)
/*************************************************************************
> File Name: myshell.c
> Author: Kris_Wqy
> Mail:
> Created Time: Mon 30 Aug 2021 08:55:15 PM CST
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#define CNT 10
#define LEN 1024
//去除命令中多余的空格
char *trim(char *str){
int head = 0;
int tail = strlen(str) - 1;
//isspace函数,判断是否是空格
while(isspace(str[head]))
head++;
while(isspace(str[tail]))
str[tail--] = 0;//用\0替代空格
return str+head;
}
//执行命令
void runcmd(char *buff){
//子进程
int redfd = -1;
//strsrt函数,返回字符串中首次出现字符的地址
if(strstr(buff, "<")){
//设置为输入重定向
redfd = 0;
}
if(strstr(buff, ">")){
//设置为输出重定向
redfd = 1;
}
char *cmd = NULL;
//判断是否有重定向符号
if(redfd != -1){
//strtok函数,用来分隔(<, >)前
char *token = strtok(buff, "<>");
//重定向前符号前为命令
cmd = token;
//分隔重定向符号后面
token = strtok(NULL, "<>");
//清理重定向符号后面的命令中多余的空格
token = trim(token);
int fd;
if(redfd){
//设置输出重定向的文件描述符
fd = open(token, O_RDWR | O_CREAT | O_TRUNC, 0644);
}else{
//设置输入重定向的文件描述符
fd = open(token, O_RDWR);
}
if(fd < 0){
perror(token);
exit(1);
}
//输出重定向,redfd指向fd
dup2(fd, redfd);
}else{//直接就是命令
cmd = buff;
}
//解析命令
int i = 0;
char *argarr[20];//指针数组
char *tk = strtok(cmd, " ");//以空格切割命令
while(tk){
argarr[i++] = tk;//把第一个命令放入指针数组
tk = strtok(NULL, " ");//继续切割命令
}
argarr[i] = tk;//空作为参数结束标志
execvp(argarr[0], argarr);//输入参数和,对应的数组
perror(argarr[0]);//执行失败
exit(1);
}
int main(){
char buff[LEN];
while(1){
printf("$");
fgets(buff, LEN, stdin);//从标准输入中读取LEN-1长度个数据,存入buff,以\n结束
buff[strlen(buff) - 1] = 0;//0就是'\0',需要把buff最后一位置为O
//printf("cmd:[%s]\n", buff);
//退出命令
if(!strcmp(buff, "exit")){
//printf("exit~\n");
break;
}
//利用管道符号|切分命令
int i = 0;
char *cmdarr[CNT];
char *tk = strtok(buff, "|");//切割原始buff里存放的命令
//cmdarr存放命令
while(tk){
cmdarr[i++] = tk;
tk = strtok(NULL, "|");
}
cmdarr[i] = tk;
//没有管道的情况
if(i == 1){
pid_t pid = fork();
if(pid < 0){
perror("fork");
exit(1);
}
if(pid){
wait(NULL);
continue;
}
runcmd(cmdarr[0]);
}
//有管道的情况
//创建管道
int pp[2];
if(pipe(pp) < 0){
perror("pipe");
exit(1);
}
//创建第一个子进程
pid_t pid = fork();
if(pid < 0){
perror("fork");
exit(1);
}
if(pid == 0){
//写端赋给标准输出,1为标准输出,pp[1]为写端
dup2(pp[1], 1);
//把管道的读写端和子进程的3,4(文件描述符)关闭
close(pp[0]);
close(pp[1]);
//执行管道前的命令
runcmd(cmdarr[0]);
}
//创建第二个子进程
pid = fork();
if(pid < 0){
perror("fork");
exit(1);
}
if(pid == 0){
//读端赋给标准输入,0为标准输入,pp[0]为读端
dup2(pp[0], 0);
//把管道的读写端和子进程的3,4(文件描述符)关闭
close(pp[0]);
close(pp[1]);
//执行管道后的命令
runcmd(cmdarr[1]);
}
//shell进程关闭管道的读端和写端
close(pp[0]);
close(pp[1]);
//wait等待子进程结束
wait(NULL);
wait(NULL);
}
return 0;
}
演示效果:
版权声明:本文为huaijiahuo_wqy原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。