问题描述
据我所知,有很多关于管道和文件重定向的信息。但是我找不到任何关于管道和文件重定向的具体信息。如果有我可能遗漏的类似内容,如果您不介意,请为我链接。
我希望能够在 shell 中执行一个命令,例如 ls -l | grep total > test.txt
,以便 grep
从 ls -l
中获取总数并将其提供给 test.txt
。
按照我的程序设置方式,所有内容都分解为 if() 逻辑以确定使用哪种符号。这是我只为管道和重定向工作的内容。当我得到一个 |
和一个 >
时,我对如何继续处理有点困惑。如何将两者结合起来?
else if(pipey && !redirect)
{
char main_str[1024];
char pipe_str[1024];
char *left_args[100] = {NULL};
char *right_args[100] = {NULL};
strcpy(main_str,string);
int fd[2];
char *token = strchr(main_str,'|');
*token = '\0';
token++;
while(*token == ' ')
{
token++;
}
strcpy(pipe_str,token);
int i = 0;
for(token = strtok(main_str," \n"),i = 0; token; token = strtok(NULL," \n" ),++i)
{
left_args[i] = token;
}
i = 0;
for(token = strtok(pipe_str,++i)
{
right_args[i] = token;
}
if(pipe(fd) == -1)
{
return 2;
}
c1_pid = fork();
if(c1_pid < 0)
{
return 3;
}
if(c1_pid == 0)
{
dup2(fd[1],STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execvp(left_args[0],left_args);
}
c2_pid = fork();
if(c2_pid < 0)
{
return 4;
}
if(c2_pid == 0)
{
dup2(fd[0],STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execvp(right_args[0],right_args);
}
close(fd[0]);
close(fd[1]);
waitpid(c1_pid,NULL,0);
waitpid(c2_pid,0);
}
// A single redirect given by user
else if(!pipey && redirect)
{
char main_str[1024];
char pipe_str[1024];
char *left_args[100] = {NULL};
char *middle_args[100] = {NULL};
char *right_args[100] = {NULL};
strcpy(main_str,string);
char *token = strchr(main_str,'>');
*token = '\0';
token++;
while(*token == ' ')
{
token++;
}
strcpy(pipe_str,++i)
{
right_args[i] = token;
}
c1_pid = fork();
if(c1_pid < 0)
{
return 5;
}
if(c1_pid == 0)
{
int file = open(right_args[0],O_WRONLY | O_CREAT,0777);
if(file == -1)
{
return 6;
}
dup2(file,STDOUT_FILENO);
execvp(left_args[0],left_args);
close(file);
}
waitpid(c1_pid,0);
}
再次,只是想知道如何获取我目前拥有的东西,并将其应用于两个符号都出现的情况。所有解析的东西都很好,只是我有点不确定的管道和重复的东西。
解决方法
将两个概念分成一个层次结构:
- 首先,管道由一个或多个用管道链接在一起的命令组成:
command | command | command
。 - 其次,命令由程序、其参数和任何重定向组成:
program arg1 arg2 arg3 >redirect1 2>redirect2 <redirect3
。
在一个函数中处理管道,在第二个从属函数中处理命令/重定向。
这将让您将这个单一的代码块分解成更小的部分。管道和重定向是正交概念。它们属于不同的、独立的功能,因此它们不必相互了解。
您还应该将解析与执行分离。智能解耦对于将代码复杂性保持在可管理的水平至关重要。
不要解析命令行和在同一代码块中执行子进程。将它们分开。进行字符串解析,拉出相关部分,然后调用单独的函数来实际fork/open/dup2/exec/waitpid。