为什么管道操作在我的 shell 中不起作用?
Why are pipe operations not working in my shell?
我正在尝试shell。
这是我用于存储命令的结构:
struct command {
char *comm;
char *args[MAX_NO_ARGS+2];
int no_args;
int order;
};
在这些函数中,我 trim 基于参数和管道运算符的命令:
char *mytrim(char *s);
int get_commands(char *line, struct command mycommands[]);
void print_command(struct command mycommands[], int no_commands);
这是我执行命令和管道处理的两个函数:
void execute_commands(struct command mycommands[], int no_commands);
int execute_command(char *command, int argc, char *args[], int fd_in, int fd_out);
当我调用 execute_commands()
进行管道处理并调用 execute_command()
进行执行而不是打印时。
我卡在了无限阅读
另外,当我尝试 (ifconfig | grep "dropped"
) 命令时,它会打印整个 ifconfig
细节,然后无限读取。
void execute_commands(struct command mycommands[], int no_commands)
{
if (no_commands == 1) {
execute_command(mycommands[0].comm, mycommands[0].no_args, mycommands[0].args, -1, -1);
} else {
int i = 0, j = 0;
int fd[no_commands-1][2];
for (i = 0; i < no_commands; i++) {
pipe(fd[i]);
}
for (i = 0; i < no_commands; i++) {
if (i == 0) {
execute_command(mycommands[i].comm, mycommands[i].no_args, mycommands[i].args, -1, fd[i][1]);
} else if (i == no_commands -1 ) {
execute_command(mycommands[i].comm, mycommands[i].no_args, mycommands[i].args, fd[i-1][0], -1);
} else {
execute_command(mycommands[i].comm, mycommands[i].no_args, mycommands[i].args, fd[i-1][0], fd[i][1]);
}
}
for (i = 0; i < no_commands-1; i++) {
close(fd[i][0]);
}
}
return;
}
int execute_command(char *command, int argc, char *args[], int fd_in, int fd_out)
{
int pid;
pid = fork();
if (pid == 0) {
if (fd_in) {
close(fd_in);
dup2(fd_in, STDIN_FILENO);
execvp(command, args);
}
if (fd_out) {
close(fd_out);
dup2(fd_out, STDOUT_FILENO);
execvp(command, args);
}
if (fd_in == fd_out == -1) {
execvp(command, args);
}
}
waitpid(pid, NULL, 0);
return 0;
}
您关闭 fds 的顺序错误。你写:
close(fd_in);
dup2(fd_in, STDIN_FILENO);
但你需要先复制:
dup2(fd_in, STDIN_FILENO);
close(fd_in);
此外,逻辑看起来很可疑。而不是:
if (fd_out) {
你可能想要
if (fd_out != 1) {
检查 if (fd_in == fd_out == -1)
几乎肯定不会像您认为的那样。 (我的意思是,您可能认为它正在检查 (fd_in == -1 && fd_out == -1)
,但事实并非如此)。您需要检查从 pipe
返回的值而不是文件描述符的值。
此外,在多个地方使用 exec
也是不正确的。您的代码当前的结构方式,假设没有错误,fd_in
将始终为非零,并且您的代码在重复 fd_in
后将 exec
。它甚至永远不会检查 fd_out
,当然也永远不会将其复制为 stdout
。您应该删除 if 子句中的 exec
,并且只调用一次 exec
。在 exec
之后你唯一应该写的代码是 perror("exec"); exit(EXIT_FAILURE);
您还应该关闭父进程中的 fd_in 和 fd_out
我正在尝试shell。
这是我用于存储命令的结构:
struct command {
char *comm;
char *args[MAX_NO_ARGS+2];
int no_args;
int order;
};
在这些函数中,我 trim 基于参数和管道运算符的命令:
char *mytrim(char *s);
int get_commands(char *line, struct command mycommands[]);
void print_command(struct command mycommands[], int no_commands);
这是我执行命令和管道处理的两个函数:
void execute_commands(struct command mycommands[], int no_commands);
int execute_command(char *command, int argc, char *args[], int fd_in, int fd_out);
当我调用 execute_commands()
进行管道处理并调用 execute_command()
进行执行而不是打印时。
我卡在了无限阅读
另外,当我尝试 (ifconfig | grep "dropped"
) 命令时,它会打印整个 ifconfig
细节,然后无限读取。
void execute_commands(struct command mycommands[], int no_commands)
{
if (no_commands == 1) {
execute_command(mycommands[0].comm, mycommands[0].no_args, mycommands[0].args, -1, -1);
} else {
int i = 0, j = 0;
int fd[no_commands-1][2];
for (i = 0; i < no_commands; i++) {
pipe(fd[i]);
}
for (i = 0; i < no_commands; i++) {
if (i == 0) {
execute_command(mycommands[i].comm, mycommands[i].no_args, mycommands[i].args, -1, fd[i][1]);
} else if (i == no_commands -1 ) {
execute_command(mycommands[i].comm, mycommands[i].no_args, mycommands[i].args, fd[i-1][0], -1);
} else {
execute_command(mycommands[i].comm, mycommands[i].no_args, mycommands[i].args, fd[i-1][0], fd[i][1]);
}
}
for (i = 0; i < no_commands-1; i++) {
close(fd[i][0]);
}
}
return;
}
int execute_command(char *command, int argc, char *args[], int fd_in, int fd_out)
{
int pid;
pid = fork();
if (pid == 0) {
if (fd_in) {
close(fd_in);
dup2(fd_in, STDIN_FILENO);
execvp(command, args);
}
if (fd_out) {
close(fd_out);
dup2(fd_out, STDOUT_FILENO);
execvp(command, args);
}
if (fd_in == fd_out == -1) {
execvp(command, args);
}
}
waitpid(pid, NULL, 0);
return 0;
}
您关闭 fds 的顺序错误。你写:
close(fd_in);
dup2(fd_in, STDIN_FILENO);
但你需要先复制:
dup2(fd_in, STDIN_FILENO);
close(fd_in);
此外,逻辑看起来很可疑。而不是:
if (fd_out) {
你可能想要
if (fd_out != 1) {
检查 if (fd_in == fd_out == -1)
几乎肯定不会像您认为的那样。 (我的意思是,您可能认为它正在检查 (fd_in == -1 && fd_out == -1)
,但事实并非如此)。您需要检查从 pipe
返回的值而不是文件描述符的值。
此外,在多个地方使用 exec
也是不正确的。您的代码当前的结构方式,假设没有错误,fd_in
将始终为非零,并且您的代码在重复 fd_in
后将 exec
。它甚至永远不会检查 fd_out
,当然也永远不会将其复制为 stdout
。您应该删除 if 子句中的 exec
,并且只调用一次 exec
。在 exec
之后你唯一应该写的代码是 perror("exec"); exit(EXIT_FAILURE);
您还应该关闭父进程中的 fd_in 和 fd_out