在我的 C 程序中使用 execvp 函数执行时 grep 挂起
grep hangs when executed using execvp function in my C program
我用 C 写了一个 bash 像 Linux shell
(Link 到我的存储库:https://github.com/oneiro-naut/wish
.文件src/execute.c
里面有execute_pipeline函数)
我在执行生成一些输出的内置命令时遇到问题。不产生任何输出的内置函数如 cd
和 exit
工作得很好。外部命令运行顺利。 Shell 支持管道结构和 I/O 重定向。问题是当我尝试 运行 一个内部命令(它只是打印一条消息)时。当我使用管道将内置命令的输出重定向到 grep 命令时,grep 子进程挂起,我认为这是因为 grep 在从管道读取时从未遇到流(或 EOF)的结尾。
注意:当管道中只有外部命令时,这不会发生。(我已经注意没有(外部)命令在下一个命令尚未开始之前完成,因此它不会挂在那里)
这是我的问题的简化版本
`
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
int main()
{
int pipe_fd[2] = {-1,-1};
int EXIT_STAT = 0;
pipe(pipe_fd);//creating pipe
char* argv[]={"grep","Radiohead",NULL};
int std_out_dup = dup(1);
dup2(pipe_fd[1],1); // redirecting stdout to parent pipe's read end
//close(pipe_fd[0]);//closing parent pipe's write end
printf("Alice in Chains\n");
printf("Radiohead\n");
printf("Dinosaur Jr.\n");
printf("Pixies\n");
printf("Soundgarden\n");
printf("Porcupine Tree\n");
printf("Pain of Salvation\n");
pid_t pid = fork();
if(pid == 0)//child process
{
dup2(pipe_fd[0],0); //redirecting grep's stdin to parent pipe's write end
close(pipe_fd[1]);
execvp(argv[0],argv);//executing grep command
perror("\n");
exit(-1);
}
else if(pid > 0)//parent process
{
int i;//closing pipes for parent
for(i=0;i<2;i++)
close(pipe_fd[i]);
do{ // waiting for grep to exit
waitpid(pid,&EXIT_STAT,WUNTRACED);
//write(,"\x4",1);
}while(!WIFEXITED(EXIT_STAT)&&!WIFSIGNALED(EXIT_STAT));
}
else ;//fork error
dup2(std_out_dup,1); // restore stdout fd for parent process
return 0;
}
`
如果我尝试 运行 它而不打印任何内容,程序就会挂起。
但是按 ^D 会终止产生输出的程序:
Alice in Chains
Radiohead
Dinosaur Jr.
Pixies
Soundgarden
Porcupine Tree
Pain of Salvation
所以 grep 似乎无法无限期地读取,因为它没有接收到任何 EOF 信号。
请指出我的错误我真的很困惑。
编辑:现在即使按 ^D 也不会终止,所以我必须只按 ^C 程序。
修正后的程序:
int main()
{
int pipe_fd[2] = {-1,-1};
int EXIT_STAT = 0;
pipe(pipe_fd);//creating pipe
char* argv[]={"grep","Radiohead",NULL};
int std_out_dup = dup(1);
//printf("%d \n",std_out_dup);
dup2(pipe_fd[1],1); // redirecting stdout to parent pipe's read end
//close(pipe_fd[0]);//closing parent pipe's write end
printf("Alice in Chains\n");
printf("Radiohead\n");
printf("Dinosaur Jr.\n");
printf("Pixies\n");
printf("Soundgarden\n");
printf("Porcupine Tree\n");
printf("Pain of Salvation\n");
fflush(stdout);
pid_t pid = fork();
if(pid == 0)//child process
{
close(pipe_fd[1]);
dup2(pipe_fd[0],0); //redirecting grep's stdin to parent pipe's write end
dup2(std_out_dup,1); // restore stdout fd for parent process
execvp(argv[0],argv);//executing grep command
perror("\n");
exit(-1);
}
else if(pid > 0)//parent process
{
int i;//closing pipes for parent
for(i=0;i<2;i++)
close(pipe_fd[i]);
dup2(std_out_dup,1); // restore stdout fd for parent process
do{ // waiting for grep to exit
waitpid(pid,&EXIT_STAT,WUNTRACED);
}while(!WIFEXITED(EXIT_STAT)&&!WIFSIGNALED(EXIT_STAT));
}
else ;//fork error
return 0;
}
你应该
1.恢复子进程中的stdout;否则 grep
子进程将写入管道的写入端,即它的标准输入。
在 if(pid == 0)//child process ... {
之后添加一个 dup2(std_out_dup,1)
2. 在所有这些 .... printf("Pain of Salvation\n");
printfs 之后添加一个 fflush(stdout)
;否则流将被刷新两次。
3.关闭父子管道的所有写端;在父级的 wait
循环之前添加 dup2(std_out_dup,1)
或 close(1)
。
我用 C 写了一个 bash 像 Linux shell
(Link 到我的存储库:https://github.com/oneiro-naut/wish
.文件src/execute.c
里面有execute_pipeline函数)
我在执行生成一些输出的内置命令时遇到问题。不产生任何输出的内置函数如 cd
和 exit
工作得很好。外部命令运行顺利。 Shell 支持管道结构和 I/O 重定向。问题是当我尝试 运行 一个内部命令(它只是打印一条消息)时。当我使用管道将内置命令的输出重定向到 grep 命令时,grep 子进程挂起,我认为这是因为 grep 在从管道读取时从未遇到流(或 EOF)的结尾。
注意:当管道中只有外部命令时,这不会发生。(我已经注意没有(外部)命令在下一个命令尚未开始之前完成,因此它不会挂在那里)
这是我的问题的简化版本 `
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
int main()
{
int pipe_fd[2] = {-1,-1};
int EXIT_STAT = 0;
pipe(pipe_fd);//creating pipe
char* argv[]={"grep","Radiohead",NULL};
int std_out_dup = dup(1);
dup2(pipe_fd[1],1); // redirecting stdout to parent pipe's read end
//close(pipe_fd[0]);//closing parent pipe's write end
printf("Alice in Chains\n");
printf("Radiohead\n");
printf("Dinosaur Jr.\n");
printf("Pixies\n");
printf("Soundgarden\n");
printf("Porcupine Tree\n");
printf("Pain of Salvation\n");
pid_t pid = fork();
if(pid == 0)//child process
{
dup2(pipe_fd[0],0); //redirecting grep's stdin to parent pipe's write end
close(pipe_fd[1]);
execvp(argv[0],argv);//executing grep command
perror("\n");
exit(-1);
}
else if(pid > 0)//parent process
{
int i;//closing pipes for parent
for(i=0;i<2;i++)
close(pipe_fd[i]);
do{ // waiting for grep to exit
waitpid(pid,&EXIT_STAT,WUNTRACED);
//write(,"\x4",1);
}while(!WIFEXITED(EXIT_STAT)&&!WIFSIGNALED(EXIT_STAT));
}
else ;//fork error
dup2(std_out_dup,1); // restore stdout fd for parent process
return 0;
}
`
如果我尝试 运行 它而不打印任何内容,程序就会挂起。
但是按 ^D 会终止产生输出的程序:
Alice in Chains
Radiohead
Dinosaur Jr.
Pixies
Soundgarden
Porcupine Tree
Pain of Salvation
所以 grep 似乎无法无限期地读取,因为它没有接收到任何 EOF 信号。 请指出我的错误我真的很困惑。
编辑:现在即使按 ^D 也不会终止,所以我必须只按 ^C 程序。
修正后的程序:
int main()
{
int pipe_fd[2] = {-1,-1};
int EXIT_STAT = 0;
pipe(pipe_fd);//creating pipe
char* argv[]={"grep","Radiohead",NULL};
int std_out_dup = dup(1);
//printf("%d \n",std_out_dup);
dup2(pipe_fd[1],1); // redirecting stdout to parent pipe's read end
//close(pipe_fd[0]);//closing parent pipe's write end
printf("Alice in Chains\n");
printf("Radiohead\n");
printf("Dinosaur Jr.\n");
printf("Pixies\n");
printf("Soundgarden\n");
printf("Porcupine Tree\n");
printf("Pain of Salvation\n");
fflush(stdout);
pid_t pid = fork();
if(pid == 0)//child process
{
close(pipe_fd[1]);
dup2(pipe_fd[0],0); //redirecting grep's stdin to parent pipe's write end
dup2(std_out_dup,1); // restore stdout fd for parent process
execvp(argv[0],argv);//executing grep command
perror("\n");
exit(-1);
}
else if(pid > 0)//parent process
{
int i;//closing pipes for parent
for(i=0;i<2;i++)
close(pipe_fd[i]);
dup2(std_out_dup,1); // restore stdout fd for parent process
do{ // waiting for grep to exit
waitpid(pid,&EXIT_STAT,WUNTRACED);
}while(!WIFEXITED(EXIT_STAT)&&!WIFSIGNALED(EXIT_STAT));
}
else ;//fork error
return 0;
}
你应该
1.恢复子进程中的stdout;否则 grep
子进程将写入管道的写入端,即它的标准输入。
在 if(pid == 0)//child process ... {
dup2(std_out_dup,1)
2. 在所有这些 .... printf("Pain of Salvation\n");
printfs 之后添加一个 fflush(stdout)
;否则流将被刷新两次。
3.关闭父子管道的所有写端;在父级的 wait
循环之前添加 dup2(std_out_dup,1)
或 close(1)
。