- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在两个子进程之间创建了一个管道
,首先,我运行 ls,它写入正确的 fd,然后,我运行 grep r
,它从正确的 fd 中读取,
我可以在终端中看到 grep
命令运行良好(输出)
问题是 grep
不会退出,它会留在那里,即使 ls
不再运行
对于其他程序,管道
工作正常..
for (i = 0; i < commands_num ; i++) { //exec all the commands instants
if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary
if (pipe(pipe_fd) == -1) {
perror("Error: \"pipe()\" failed");
}
pcommands[i]._fd_out = pipe_fd[1];
pcommands[i+1]._fd_in = pipe_fd[0];
}
pid = fork(); //the child exec the commands
if (pid == -1) {
perror("Error: \"fork()\" failed");
break;
} else if (!pid) { //child process
if (pcommands[i]._flag_pipe_in == 1) { //if there was a pipe to this command
if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_in);
}
if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_out);
}
execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
perror("Error: \"execvp()\" failed");
exit(0);
} else if (pid > 0) { //father process
waitpid(pid, NULL, WUNTRACED);
}
}
//closing all the open fd's
for (i = 0; i < commands_num ; i++) {
if (pcommands[i]._fd_in != STDIN) { //if there was an other stdin that is not 0
close(pcommands[i]._fd_in);
}
if (pcommands[i]._fd_out != STDOUT) { //if there was an other stdout that is not 1
close(pcommands[i]._fd_out);
}
}
所以,我有一个“命令”即时 pcommands[i]
它有:管道输入、管道输出的标志fdin,fdout,和一个 char** (对于真正的命令,如“ls -l”)
可以说一切都很好,这意味着:
pcommands[0]:
pipein=0
pipeout=1
char** = {"ls","-l",NULL}
pcommands[1]:
pipein=1
pipeout=0
char** = {"grep","r",NULL}
现在,循环将进行两次(因为我有两个命令瞬间)第一次,它会看到pcommands[0]有pipeout==1创建管道做 fork pcommands[0] 有 pipelineout==1子: dup2 到标准输出execvp
第二次:不创建管道做 fork child :pcomands[1] 有 pipelinein==1然后: dup2 到输入执行程序..
这个命令有效,我的输出是:
errors.log exer2.pdf multipal_try
(所有带有“r”的内容)但随后它就卡住了,并且无法退出grep
..在另一个终端中我可以看到 grep
仍在工作
我希望我关闭所有需要关闭的 fd...
我不明白为什么它不起作用,看起来我做得对(嗯,它适用于其他命令..)
有人可以帮忙吗?谢谢
最佳答案
您没有关闭足够的管道文件描述符。
dup()
或 dup2()
将管道文件描述符复制到标准输入或标准输出,则应关闭两者 原始管道文件描述符。您还需要确保,如果父 shell 创建管道,它会关闭管道文件描述符的两个副本。
另请注意,管道中的进程应允许同时运行。特别是,管道的容量有限,当管道中没有剩余空间时,进程就会阻塞。该限制可以非常小(POSIX 要求它必须至少为 4 KiB,但仅此而已)。如果您的程序处理兆字节的数据,则必须允许它们在管道中同时运行。因此,waitpid()
应该发生在启动子进程的循环之外。等待之前还需要关闭父进程中的管道;否则,读取管道的子进程将永远不会看到 EOF(因为理论上,父进程可以写入管道,即使它不会)。
您的结构成员的名称以下划线开头。那很危险。以下划线开头的名称保留用于实现。 C 标准说:
ISO/IEC 9899:2011 §7.1.3 Reserved Identifiers
— All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
— All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
这意味着如果您遇到问题,那么问题是您的,而不是系统的。显然,您的代码可以工作,但您应该意识到可能遇到的问题,并且最好避免它们。
<小时/>这是一个基于上面代码的固定 SSCCE:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct Command Command;
struct Command
{
int _fd_out;
int _fd_in;
int _flag_pipe_in;
int _flag_pipe_out;
char **_commands;
};
typedef int Pipe[2];
enum { STDIN = STDIN_FILENO, STDOUT = STDOUT_FILENO, STDERR = STDERR_FILENO };
int main(void)
{
char *ls_cmd[] = { "ls", 0 };
char *grep_cmd[] = { "grep", "r", 0 };
Command commands[] =
{
{
._fd_in = 0, ._flag_pipe_in = 0,
._fd_out = 1, ._flag_pipe_out = 1,
._commands = ls_cmd,
},
{
._fd_in = 0, ._flag_pipe_in = 1,
._fd_out = 1, ._flag_pipe_out = 0,
._commands = grep_cmd,
}
};
int commands_num = sizeof(commands) / sizeof(commands[0]);
/* Allow valgrind to check memory */
Command *pcommands = malloc(commands_num * sizeof(Command));
for (int i = 0; i < commands_num; i++)
pcommands[i] = commands[i];
for (int i = 0; i < commands_num; i++) { //exec all the commands instants
if (pcommands[i]._flag_pipe_out == 1) { //creates pipe if necessary
Pipe pipe_fd;
if (pipe(pipe_fd) == -1) {
perror("Error: \"pipe()\" failed");
}
pcommands[i]._fd_out = pipe_fd[1];
pcommands[i+1]._fd_in = pipe_fd[0];
}
pid_t pid = fork(); //the child exec the commands
if (pid == -1) {
perror("Error: \"fork()\" failed");
break;
} else if (!pid) { //child process
if (pcommands[i]._flag_pipe_in == 1) { //if there was a pipe to this command
assert(i > 0);
assert(pcommands[i-1]._flag_pipe_out == 1);
assert(pcommands[i-1]._fd_out > STDERR);
if (dup2(pcommands[i]._fd_in, STDIN) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_in);
close(pcommands[i-1]._fd_out);
}
if (pcommands[i]._flag_pipe_out == 1) { //if there was a pipe from this command
assert(i < commands_num - 1);
assert(pcommands[i+1]._flag_pipe_in == 1);
assert(pcommands[i+1]._fd_in > STDERR);
if (dup2(pcommands[i]._fd_out, STDOUT) == -1) {
perror("Error: \"dup2()\" failed");
exit(0);
}
close(pcommands[i]._fd_out);
close(pcommands[i+1]._fd_in);
}
execvp(pcommands[i]._commands[0] , pcommands[i]._commands); //run the command
perror("Error: \"execvp()\" failed");
exit(1);
}
else
printf("Child PID %d running\n", (int)pid);
}
//closing all the open pipe fd's
for (int i = 0; i < commands_num; i++) {
if (pcommands[i]._fd_in != STDIN) { //if there was another stdin that is not 0
close(pcommands[i]._fd_in);
}
if (pcommands[i]._fd_out != STDOUT) { //if there was another stdout that is not 1
close(pcommands[i]._fd_out);
}
}
int status;
pid_t corpse;
while ((corpse = waitpid(-1, &status, 0)) > 0)
printf("Child PID %d died with status 0x%.4X\n", (int)corpse, status);
free(pcommands);
return(0);
}
Just for my knowledge, how would you do it, so it won't get "indisputably messy"?
我可能会保留管道信息,以便 child 不需要担心断言中包含的条件(在管道中访问 child 之前或之后的 child 信息)。如果每个 child 只需要访问自己数据结构中的信息,那就更干净了。我将重新组织“struct Command”,使其包含两个管道,以及哪个管道包含需要关闭的信息的指示器。在很多方面,与你所拥有的并没有根本不同;只是那个 child i更整洁,只需要查看pcommands[i]
。
您可以在不同的上下文中看到部分答案:C Minishell adding pipelines .
关于c - 尝试用 "ls | grep r"运行 "execvp()",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13693446/
POSIX 系统公开了一系列 exec 函数,这些函数允许将可能不同的东西加载到当前进程中,保持打开的文件描述符、进程标识符等。 这可以出于多种原因完成,在我的例子中,这是自举——我想更改我自己进程的
我有一个用 c 编写的程序,它使用 execvpe(3) 函数,并且我设置了一行以包含必需的头文件: #include 我使用以下命令编译此文件... gcc foo.c -o foo ...仅收到
我在 C 中有一个函数,它创建一个子进程并使其运行 execvp。 int Execute(char **arg) { pid_t pid; int status; if ((
我正在使用 C 编写一个非常基本的 UNIX shell。在这个项目中,我试图使用 fork() 和 execvp() 来执行实际的 shell命令。我遇到了一个问题,它似乎可以很好地处理具有单个参数
我无法获得使用 execvp 调用的程序的完整输出。在这里,我基本上是在尝试用一个可以过滤输入和输出的程序来包装任何程序: #define BUF_SIZ 8192 int main(int argc
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我正在尝试用 c 语言创建一个 shell,当前正在尝试 ls 命令,但子进程总是返回 execvp 无法工作。这是函数。首先,我使用 exec 获取我所在的路径和从 stdin 获取的命令,这就是为
我正在开发这个程序,使用系统调用 execvp() 和 fork() 来运行通过命令行参数给出的 shell 命令。这里 arglist 是一个二维数组,其中包含命令名称及其参数列表。我将命令名称作为
我尝试使用 execvp 创建一个作为参数给出的存储库。但我遇到了一些无法在以下代码中解决的段错误(核心转储): #include //mkdir #include #include //p
我正在尝试使用 execvp 对文件进行排序,这是我的代码。 char *argv1[]={ "sh", "-c", "sort input.txt > output.txt", NULL }; 问题
我正在c中测试execvpe(),我尝试了下面的代码,这导致错误“函数‘execvpe’的隐式声明在C99 [-Wimplicit-function-declaration]中无效”。 #includ
我有以下代码: int main(int argc, char *argv[]) { int i, a=9; int length = 0; c
我正在使用 execvp() 运行一些系统调用。程序对于有效命令非常有效,对于任何不存在的命令则失败,这是完美的。该程序是,当我在需要额外参数(如 cat)的命令上使用 execvp() 并且我不提供
用户将读取一行,我将保留第一个单词作为 execvp 的命令。 假设他将输入“cat file.txt” ...命令将为 cat 。但我不知道如何使用这个execvp(),我读了一些教程但仍然没有明白
我正在用 C 编程编写一个正在运行的 shell 脚本。我读过有关 exec 函数的内容,虽然不太了解,但我读过一个像这样使用 execvp 的示例 execvp(*argv, argv) ; /*
这是我的输入函数: int i,j,n,len,c; char *buffer = 0; size_t bufsize = 0; ssize_t characters;
我正在尝试编写一个程序,该程序将 fork ,然后打开一个文件并执行它。它应该执行的文件称为子文件,并且它已经被编译。当我输入 ./child 时,它就会运行。但是,当我运行该程序时,它不会执行子程序
所以我有一个 C 程序,它接受命令输入,但偶尔我似乎会遇到某种内存错误。 我如何读取输入: static void parseLine(char* commandLine, Sequence* seq
我尝试在终端中传递命令行参数“ls -l/user/myuser”并在主目录中执行 execvp。 但不知何故,当我调试代码时,它给了我这个错误。 int main(int argc, char *a
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
我是一名优秀的程序员,十分优秀!