minishell支持重定向
支持重定向的核心逻辑:
1.分析字符串是否含有重定向的符号,并且提取文件名。
#define INPUT_REDIR 0 //输入重定向
#define OUTPUT_REDIR 1 //输出重定向
#define APPEND_REDIR 2 //追加重定向
#define NONE_REDIR 4 //没有重定向
int redir_status = NONE_REDIR;//状态
char* CheckRedir(char* start)
{
assert(start);
char* end = start + strlen(start)-1;
//end执行指令的最后一个内容
while(start < end)
{
if(*end == '>')
{
if(*(end -1) == '>')
{
//ls -a -l>>log.txt\0 追加
redir_status = APPEND_REDIR;
*(end-1) = '\0';
end++;
break;
}
//ls -a -l>log.txt\0 输出
redir_status = OUTPUT_REDIR;
*(end) = '\0';
end++;
break;
}
else if(*end == '<')
{
//ls -a -l<log.txt\0 输入
redir_status = INPUT_REDIR;
*end = '\0';
end++;
break;
}
else
{
end--;
}
}
//循环结束,如果end还是大于start,说明存在重定向
if(end > start)
{
return end;
}
//走到这说明不存在重定向
return NULL;
}
例子:
end开始向前找重定向符
然后end++
这样end指向的就是文件名,start执行的就是指令内容。
然后就开始在子进程进行重定向了。
//printf("parent process create subprocess success\n");
if(sep)
{
int fd = -1;
switch(redir_status)
{
case INPUT_REDIR:
fd = open(sep,O_RDONLY);
dup2(fd,0);
break;
case OUTPUT_REDIR:
fd = open(sep,O_WRONLY | O_CREAT | O_TRUNC,0666);
dup2(fd,1);
break;
case APPEND_REDIR:
fd = open(sep,O_WRONLY | O_CREAT | O_APPEND,0666);
dup2(fd,1);
break;
default:
assert(NULL);
break;
}
}
minishell完整代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <assert.h>
#define NUM 1024
#define SIZE 32
#define SEP " "
#define INPUT_REDIR 0
#define OUTPUT_REDIR 1
#define APPEND_REDIR 2
#define NONE_REDIR 4
int redir_status = NONE_REDIR;
char cmd_line[NUM];//array for saving command line
char* g_argv[SIZE];//the array are used to store paresed commands
char g_myval[64];
char* CheckRedir(char* start)
{
assert(start);
char* end = start + strlen(start)-1;
while(start < end)
{
if(*end == '>')
{
if(*(end -1) == '>')
{
//ls -a -l>>log.txt\0
redir_status = APPEND_REDIR;
*(end-1) = '\0';
end++;
break;
}
//ls -a -l>log.txt\0
redir_status = OUTPUT_REDIR;
*(end) = '\0';
end++;
break;
}
else if(*end == '<')
{
//ls -a -l<log.txt\0
redir_status = INPUT_REDIR;
*end = '\0';
end++;
break;
}
else
{
end--;
}
}
if(end > start)
{
return end;
}
return NULL;
}
int main()
{
//1.命令行解释器,一定是一个常驻内存的进程,不退出
while(1)
{
//2.显示提示行
printf("[xiaolin@localhost myshell]#");
fflush(stdout);
memset(cmd_line,'\0',sizeof cmd_line);
//3.获取用户输入的字符串
if(fgets(cmd_line,sizeof cmd_line,stdin) == NULL)
{
//if cmd_line empty contiue get command
continue;
}
cmd_line[strlen(cmd_line)-1] = '\0';
char* sep = CheckRedir(cmd_line);
//4.对字符串进行解析
int index = 0;
g_argv[index++] = strtok(cmd_line,SEP);//Firest parse cmd_line
while(1)//Second parse cmd_line don't pass cmdline;
{
g_argv[index] = strtok(NULL,SEP);
if(g_argv[index] == NULL) break;
index++;
}
if(strcmp(g_argv[0],"ls") == 0)
{
g_argv[index++] = (char*)"--color=auto";
g_argv[index] = NULL;
}
if(strcmp(g_argv[0],"ll") == 0)
{
g_argv[0] = (char*)"ls";
g_argv[1] = (char*)"-l";
g_argv[2] = (char*)"--color=auto";
g_argv[3] = NULL;
}
// processing of built-in commands
if(strcmp(g_argv[0],"cd") == 0)
{
//chdir() changes the current working directory of the calling process to the directory specified in path.
if(g_argv[1] != NULL) chdir(g_argv[1]);
continue;
}
if(strcmp(g_argv[0],"export") == 0 && g_argv[1] != NULL)
{
//There is a very hidden issue here
//Ptuenv passes an environment variable as a pointer to it
//And g_ Argv [1] will be cleared on the next command_line read
//In this way, the environment variable pointer points to a place with empty data, and this pointer is also a null pointer
//int res = putenv(g_argv[1]);
//if(res == 0) printf("export success\n");
//else printf("export fail\n");
//solve the problem
strcpy(g_myval,g_argv[1]);
int res = putenv(g_myval);
if(res == 0) printf("export success\n");
else printf("expor fail\n");
continue;
}
/*//test if the g_argv array id correct
for(index = 0; g_argv[index]; index++)
{
printf("g_argv[%d]:%s\n",index,g_argv[index]);
}*/
//5.create subprocess execute command
pid_t id = fork();
if(id == 0)
{
//subprocess
//printf("parent process create subprocess success\n");
if(sep)
{
int fd = -1;
switch(redir_status)
{
case INPUT_REDIR:
fd = open(sep,O_RDONLY);
dup2(fd,0);
break;
case OUTPUT_REDIR:
fd = open(sep,O_WRONLY | O_CREAT | O_TRUNC,0666);
dup2(fd,1);
break;
case APPEND_REDIR:
fd = open(sep,O_WRONLY | O_CREAT | O_APPEND,0666);
dup2(fd,1);
break;
default:
assert(NULL);
break;
}
}
printf("subprocess starts running\n");
execvp(g_argv[0],g_argv);
printf("subprocess replace fail\n");
}
else if(id > 0)
{
//parent process
int status = 0;
pid_t res = waitpid(-1,&status,0);//blocking waiting
if(res == -1)
{
printf("parent process wait subprocess fail\n");
}
else if(res > 0)
{
printf("parent process wait subprocess success exit_code:%d\n",WEXITSTATUS(status));
}
else
{
printf("unkown error\n");
}
}
else
{
//fail
printf("parent procrss create subprocess fail\n");
}
}
return 0;
}