我需要实现处理多个管道命令的
shell.例如,我需要能够处理这个:ls | grep -i cs340 |排序| uniq | cut -c 5.我假设问题是我没有将前一个命令的输出传递给下一个命令的输入.
当我执行我的代码时,它没有给我输出.我正在使用这个伪代码:
for cmd in cmds
if there is a next cmd
pipe(new_fds)
fork
if child
if there is a previous cmd
dup2(old_fds[0], 0)
close(old_fds[0])
close(old_fds[1])
if there is a next cmd
close(new_fds[0])
dup2(new_fds[1], 1)
close(new_fds[1])
exec cmd || die
else
if there is a previous cmd
close(old_fds[0])
close(old_fds[1])
if there is a next cmd
old_fds = new_fds
if there are multiple cmds
close(old_fds[0])
close(old_fds[1])
以下是处理多个管道的函数的源代码.
void execute_multiple_commands(struct command ** commands_to_exec,
int num_commands_p)
{
pid_t status;
int i, err;
int new_fd[2], old_fd[2];
pid_t pid, cpid;
// creating child process
if ( (cpid = fork()) == -1)
{
fprintf(stderr, "Could not create child process, exiting...");
exit(1);
}
if (cpid == 0) // in the child process we run multiple pipe handling
{
for (i = 0; i < num_commands_p; i++) // for each cmd in cmds
{
if (i+1 < num_commands_p) // if there is next cmd
pipe(new_fd);
if ( (pid = fork()) == -1)
{
fprintf(stderr, "Could not create child process, exiting...");
exit(1);
}
if (pid == 0) // if child
{
if (i != 0) // if there is a previous command
{
dup2(old_fd[0], 0); // setting up old_pipe to input into the child
close(old_fd[0]);
close(old_fd[1]);
}
if (i+1 < num_commands_p) // if there is a next cmd
{
close(new_fd[0]); // setting up new_pipe to get output from child
dup2(new_fd[1], 1);
close(new_fd[1]);
err = execvp(commands_to_exec[i]->args[0], commands_to_exec[i]->args);
status = err;
exit(err);
}
}
else
{
waitpid(pid, &status, 0);
if (status == -1)
exit(1);
if (i != 0) // if there a previous command
{
close(old_fd[0]);
close(old_fd[1]);
}
if (i+1 < num_commands_p) // if there a next cmd
{
old_fd[0] = new_fd[0];
old_fd[1] = new_fd[1];
}
exit(0);
} // end if
} // end for
if (i) // if there a multiple commands
{
close(old_fd[0]);
close(old_fd[1]);
}
}
else // in the parent process we are waiting for child to handle multiple pipes
waitpid(cpid, &status, 0);
}
函数execvp()接受结构数组.我检查了所有解析部分,它工作正常.这是execute_multiple_commands()函数,我遇到了麻烦.
这是struct的代码:
// name: command
// desc: holds one command (meaning that it can be
// more than one token in that command)
// "ls -la" will be an example of one command
// holds num of tokens in command array
struct command
{
char ** args;
int num_args;
};
最佳答案 我建议一个新的策略,R2:
function do(commands)
if commands is of size 1
exec commands[0] || die
split commands into c1 (first command) c2 (the rest of them)
open
if fork
close input end of pipe
dup output of pipe to stdin
do (c2) || die
close output end of pipe
dup input of pipe to stdout
exec c1 || die
使用递归函数,尤其是在维护列表时,将帮助您简化逻辑.你真的不必担心堆栈深度,因为你的整个地址空间都会被覆盖.
在其他新闻中,来自man page:
After a successful return from one of these system calls, the old and
new file descriptors may be used interchangeably. They refer to the
same open file description (see open(2)) and thus share file offset
and file status flags; for example, if the file offset is modified by
using lseek(2) on one of the descriptors, the offset is also changed
for the other.
当你说你关闭管道的两端时,这意味着什么?你真的在关闭它 – 它和你的程序打算使用的标准输入/输出.
– >多次编辑< – 正如Jonathan Leffler指出的那样,上述信息是正确的.我用以下程序确认了它:
#include <unistd.h>
int main(){
dup2(0, 7);
write(7, "Hey, 1\n", 7);
close(0);
write(7, "Hey, 2\n", 7);
close(7);
write(7, "Hey, 3\n", 7);
}
这导致以下输出:
$gcc dup2Test.c && ./a.out
Hey, 1
Hey, 2
谢谢你,乔纳森!