我知道有很多主题可以讨论这个问题,但我真的不明白它的实现方式。
我正在尝试创建一个可以执行linux命令的shell,如ps | grep | less
我通过将每个命令及其args放在一个简单的链表中来完成解析。
这是我的实现不起作用。希望这很清楚。
if ((son = fork()) < 0)
return printerr_sys("Unable to fork", 0);
if (son == 0)
{
if (first > 1 && data->format[first - 1] &&
is_directing_elt(data->format[first - 1]) == DIRECT_TPIPE)
dup2(tube_p[0], STDIN_FILENO);
first = make_argv(data, first, &argv);
if (next)
{
dup2(tube_v[1], STDOUT_FILENO);
close(tube_v[0]);
}
if (execvp(argv[0], argv) < 0)
return printerr_cmd(argv[0], 1);
}
else
{
if (next)
{
close(tube_v[1]);
cmdline_executer(data, next, tube_v);
}
waitpid(son, &(data->lastcmd), WUNTRACED);
data->lastcmd = WEXITSTATUS(data->lastcmd);
}
return TRUE;
我的问题是:
答案 0 :(得分:5)
这是我在计算机科学职业生涯中必须在C中实现操作系统主题的UNIX Shell的一部分。
/* Executes the command 'buffer' assuming that doesn't contain redirections */
void execute_only_pipes(char* buffer)
{
char *temp = NULL, *pipeCommands[MAX_PIPES], *cmdArgs[MAX_ARGUMENTS];
int newPipe[2], oldPipe[2], pipesCount, aCount, i, status;
pid_t pid;
pipesCount = -1; /* This variable will contain how many pipes the command contains */
/* Counting the number of pipes and splitting them into pipeCommands */
do
{
temp = strsep(&buffer, "|");
if(temp != NULL)
{
if(strlen(temp) > 0)
{
pipeCommands[++pipesCount] = temp;
}
}
} while(temp);
cmdArgs[++pipesCount] = NULL;
for(i = 0; i < pipesCount; i++) /* For each command */
{
aCount = -1;
/* Parsing command & arguments */
do
{
temp = strsep(&pipeCommands[i], " ");
if(temp != NULL)
{
if(strlen(temp) > 0)
{
/* If a parameter is ~, then replace it by /home/user */
if (!strcmp(temp, "~"))
strcpy(temp, home);
cmdArgs[++aCount] = temp;
}
}
} while(temp);
cmdArgs[++aCount] = NULL;
/* If there still are commands to be executed */
if(i < pipesCount-1)
{
pipe(newPipe); /* just create a pipe */
}
pid = fork();
if(pid == 0) /* Child */
{
/* If there is a previous command */
if(i > 0)
{
close(oldPipe[1]);
dup2(oldPipe[0], 0);
close(oldPipe[0]);
}
/* If there still are commands to be executed */
if(i < pipesCount-1)
{
close(newPipe[0]);
dup2(newPipe[1], 1);
close(newPipe[1]);
}
/* Execute it */
int res = execvp(cmdArgs[0], cmdArgs);
if (res == -1)
{
printf("Error. Command not found: %s\n", cmdArgs[0]);
}
exit(1);
}
else /* Father */
{
/* If there is a previous command */
if(i > 0)
{
close(oldPipe[0]);
close(oldPipe[1]);
}
/* do we have a next command? */
if(i < pipesCount-1)
{
oldPipe[0] = newPipe[0];
oldPipe[1] = newPipe[1];
}
/* wait for last command process? */
if(i == pipesCount-1)
{
waitpid(pid, &status, 0);
}
}
}
}
这可能是一个小小的车(我不会检查是否fork() < 0
等),但主要想法是正确的。
&GT;是否可以通过递归来实现?
大部分时间我都试图避免递归,如果我可以编写类似的可理解的代码而不使用它。
答案 1 :(得分:0)
进程独立运行,所以你需要在fork之前为至少第一对命令设置管道,但是你在子进程中这样做(son == 0)。你可以编写一个递归解决方案,只要剩下至少两个命令,就会创建一个管道,然后分叉,然后运行第一个命令。