自己写的shell程序 多层管道、重定向、后台、命令历史
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<stdbool.h>
#include<signal.h>
#include <readline/readline.h>
#include <readline/history.h>
//#include<errno.h>
//#include<sys/stat.h>
#define MAX_LINE_SIZE 100
#define MAX_ARGC 20 //最多20个参数
#define MAX_ARGLEN 50 //每个参数最大长度
#define MAX_FILE_NAME 100
#define FIFO "/tmp/my_fifo"
FILE *his;
char *temp,*temp1,*fileName;
static char *line_read = (char *)NULL;
char* nextcmd;
char *argv[MAX_ARGC];
unsigned char argc=0;
bool is_pipe;
char buf[1000];
bool is_bg;
bool fromsigc = false;
void sig_child(int n){}
void sig_C(int n)
{
printf("\n[COMMAND_LINE_$] ");
fflush(stdout);
fromsigc = true;
return;
}
//提取参数
void divArgs(char* argv[],char* cmd)
{
int argc=0;
while((argv[argc] = (char*)malloc(sizeof(char)*MAX_ARGLEN)) &&
EOF!=sscanf(cmd,"%s",argv[argc]) && argc<=MAX_ARGC)
{
while(isspace(cmd[0])) cmd++;
cmd+=strlen(argv[argc++]);
}
argv[argc] = NULL;
}
//输入命令
char *rl_gets()
{
if(line_read)
{
free (line_read);
line_read = (char *)NULL;
}
if(fromsigc)
line_read = readline(NULL);
else
line_read = readline("[COMMAND_LINE_$] ");
fromsigc = false;
if(line_read && *line_read)
add_history(line_read);
return(line_read);
}
void trim_tail(char* str)
{
int i=strlen(str)-1;
for(;isspace(str[i]);str[i--]='\0');
}
char* trim(char* str)
{
while(isspace(*str))
str++;
trim_tail(str);
return str;
}
bool isbg(char* str)
{
bool flag = false;
int i=strlen(str)-1;
for(;isspace(str[i]) || str[i]=='&';str[i--]='\0')
if(str[i]=='&')
flag = true;
return flag;
}
void div_and_deal(char* str,char* delim,void (*fn)(void*))
{
char *token=0;
for(token=strtok(str,delim);token!=NULL;token=strtok(NULL,delim))
{
(*fn)(token);
}
}
bool deal_redirect(char* cmd, int *rd, int *in, int *out)
{
char *p;
int i=0;
// rd: null:0 <:1 >>2 >3
while((p=strchr(cmd,'<')) || (p=strchr(cmd,'>'))){
i = 0;
*rd = 3;
if(p[0]=='<')
*rd = 1;
*p++ = ' ';
if((*rd !=1) && (p[0]=='>')){
*rd = 2;
*p++ = ' ';
}
while(isspace(*p)) p++;
if(!p)
return false;
char fp[MAX_FILE_NAME];
while(p && *p!='\0' && *p!='>' && *p!='<' && !isspace(*p)){
fp[i++] = *p;
*p++ = ' ';
}
fp[i]='\0';
if(*rd == 1)
*in = open(fp,O_RDONLY);
else if(*rd == 2)
*out = open(fp,O_WRONLY | O_CREAT | O_APPEND,0664);
else
*out = open(fp,O_WRONLY | O_CREAT | O_TRUNC,0664);
}
}
void execute(char* cmd,int in, int out)
{
pid_t pid,pid1,pid2;
char *cmd1,*cmd2,*p;
int fd;
int status;
int rd = 0;
if(p=strchr(cmd,'|'))
{
cmd1=cmd;
cmd2=p+1;
*p='\0';
deal_redirect(cmd1, &rd, &in, &out);
divArgs(argv,cmd1);
unlink(FIFO);
mkfifo(FIFO, 0666);
if((pid1=fork())==0){
fd=open(FIFO,O_WRONLY);
dup2(fd,STDOUT_FILENO);
dup2(in,STDIN_FILENO);
dup2(out,STDOUT_FILENO);
if(execvp(argv[0],argv)<0){
printf("cmd error!\n");
close(fd);
}
}else{
if((pid1=fork())==0){
fd = open(FIFO, O_RDONLY);
if(rd != 2 && rd != 3)
in = fd;
execute(cmd2,in,STDOUT_FILENO);
close(fd);
exit(0);
}else{
if(!is_bg){
waitpid(pid1,&status,0);
waitpid(pid2,&status,0);
}
}
}
}else{
deal_redirect(cmd, &rd, &in, &out);
divArgs(argv,cmd);
if((pid=fork())==0){
dup2(in,STDIN_FILENO);
dup2(out,STDOUT_FILENO);
if(execvp(argv[0],argv)<0){
printf("error\n");
exit(-1);
}
}else{
if(!is_bg)
waitpid(pid,&status,0);
}
}
if(in != STDIN_FILENO) close(in);
if(out != STDOUT_FILENO) close(out);
for(argc;argc>0;free(argv[argc]))argc--;
}
void execmd(char* cmd)
{
//bg
is_bg = isbg(cmd);
char* command = strdup(cmd);
execute(command,STDIN_FILENO,STDOUT_FILENO);
}
int main()
{
signal(SIGINT,sig_C);
signal(SIGCHLD,sig_child);
printf("*************shell*************\n");
while(true)
{
char * line_=trim(rl_gets());
//退出
if(!strcmp(line_,"exit"))
{
break;
}
//没有输入
if(line_[0]=='\0')
{
continue;
}
temp1=temp = strdup(line_);
//执行
div_and_deal(temp,";",(void (*)(void*))execmd);
free(temp1);
}
return 0;
}
readline 库的使用方法:http://www.cnblogs.com/pswzone/archive/2012/04/14/2446796.html