- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我实际上正在致力于在 shell 中实现多管道,我必须说我正在解决我在项目中遇到的一些问题。
一个特殊的细节使得这个多管道实现相当困难,它必须在文件描述符的非常低的限制下工作。
例如,如果您在 bash 或 tcsh 上输入命令“限制描述符 10”,您仍然可以运行很长的命令,例如“ls|cat|cat|cat|cat|cat|cat|cat|cat|cat|cat” |cat|cat|wc”,没有任何错误消息或损坏的管道。
我的多管也必须这样做。
我一直在研究这个问题并提出了几个不同的版本。最后一个似乎可以部分工作,但不符合真实外壳的显示。我所做的是创建一棵树来执行命令“cat|ls|wc”。
在真实的 shell 中,“wc”应该显示其结果,然后“cat”应该在退出之前等待接收一个用户输入。
在我的版本中,“cat”循环首先出现等待用户输入,然后让 wc 显示结果并退出。
我的“wc”显示了良好的结果,只是看起来它的执行被延迟了。就好像它正在等待从管道或其他东西接收信号......我不明白为什么“wc”没有立即显示我可能没有正确关闭或欺骗管道?
您将在这些行后面找到我的代码。
预先感谢您给我的任何帮助或提示。
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#define PIPE 1
#define CMD 2
typedef struct s_tree
{
char *cmd;
int fd[2];
char type;
struct s_tree *left;
struct s_tree *right;
struct s_tree *parent;
} t_tree;
/*
static void test_tree(t_tree *tree)
{
if (tree == NULL)
{
printf("Null\n");
return ;
}
if (tree->type == PIPE)
printf("Type pipe\n");
else if (tree->type == CMD)
printf("Type cmd : %s\n", tree->cmd);
if (tree->left != NULL)
{
printf("Gauche\n");
test_tree(tree->left);
}
if (tree->right != NULL)
{
printf("Droite\n");
test_tree(tree->right);
}
}
*/
void my_exit(int value)
{
fprintf(stderr, "EXITING %d\n", value);
perror(NULL);
exit(value);
}
int execute_cmd(t_tree *tree)
{
if (execlp(tree->cmd, tree->cmd, NULL) < 0)
my_exit(11);
return (0);
}
int execute_pipe(t_tree *tree)
{
int statusleft;
int statusright;
pid_t pidright;
pid_t pidleft;
int fd[2];
if (pipe(fd) < 0)
my_exit(1);
if ((pidleft = fork()) < 0)
my_exit(2);
if (pidleft == 0)
{
if (close(fd[1]) < 0
|| close(0) < 0)
my_exit(3);
if (dup2(fd[0], 0) < 0)
my_exit(4);
if (tree->left->type == PIPE)
return (execute_pipe(tree->left));
else if (tree->left->type == CMD)
return (execute_cmd(tree->left));
}
else
{
if (close(fd[0]) < 0
|| close(1) < 0)
my_exit(6);
if ((pidright = fork()) < 0)
my_exit(5);
if (pidright == 0)
{
if (dup2(fd[1], 1) < 0)
my_exit(7);
if (tree->right->type == PIPE)
return (execute_pipe(tree->right));
else if (tree->right->type == CMD)
return (execute_cmd(tree->right));
}
else
{
if (close(fd[1]) < 0
|| close(0) < 0)
my_exit(8);
if (waitpid(pidright, &statusright, 0) < 0)
my_exit(9);
}
if (waitpid(pidleft, &statusleft, 0) < 0)
my_exit(10);
}
return (0);
}
/*
** PIPE
** /\
** / \
** / \
** wc PIPE
** /\
** / \
** / \
** ls cat
**
** cat | ls | wc
*/
int main(int ac, char **av)
{
t_tree *tree;
tree = malloc(sizeof(*tree));
tree->left = malloc(sizeof(*tree));
tree->right = malloc(sizeof(*tree));
tree->right->left = malloc(sizeof(*tree));
tree->right->right = malloc(sizeof(*tree));
tree->type = PIPE;
tree->left->right = NULL;
tree->left->left = NULL;
tree->left->type = CMD;
tree->left->cmd = malloc(strlen("/usr/bin/wc") + 1);
strcpy(tree->left->cmd, "/usr/bin/wc");
tree->right->type = PIPE;
tree->right->left->right = NULL;
tree->right->left->left = NULL;
tree->right->left->type = CMD;
tree->right->left->cmd = malloc(strlen("/bin/ls") + 1);
strcpy(tree->right->left->cmd, "/bin/ls");
tree->right->right->left = NULL;
tree->right->right->left = NULL;
tree->right->right->type = CMD;
tree->right->right->cmd = malloc(strlen("/bin/cat") + 1);
strcpy(tree->right->right->cmd, "/bin/cat");
tree->parent = NULL;
tree->left->parent = tree;
tree->right->parent = tree;
tree->right->left->parent = tree->right;
tree->right->right->parent = tree->right;
/*test_tree(tree);*/
return (execute_pipe(tree));
}
最佳答案
这是代码的检测版本及其输出。
$ nsh
4625: Main shell
4625: Node type 1
4625: Left: 0x7FBFE8403980, Right: 0x7FBFE84039A0
4625: Pipe: r 3, w 4
Parent 4625 - waiting for R-Child (4627)
4625: ooo-o-----
4626: L-Child
4627: R-Child
4626: ooooo-----
4627: ooo-o-----
4627: Node type 1
4627: Left: 0x7FBFE84039C0, Right: 0x7FBFE84039E0
4626: Node type 2
4626: Command: /usr/bin/wc
4627: Pipe: r 3, w 4
4626: Left: 0x000000000000, Right: 0x000000000000
4626: Command: /usr/bin/wc
4626: ooo-------
Parent 4627 - waiting for R-Child (4629)
4627: ooo-o-----
4629: R-Child
4628: L-Child
4629: ooo-o-----
4629: Node type 2
4629: Command: /bin/cat
4628: ooooo-----
4629: Left: 0x000000000000, Right: 0x000000000000
4629: Command: /bin/cat
4629: ooo-------
4628: Node type 2
4628: Command: /bin/ls
4628: Left: 0x000000000000, Right: 0x000000000000
4628: Command: /bin/ls
4628: ooo-------
Parent 4627 - R-Child died 4629 = 0x000D
Parent 4627 - waiting for L-Child (4628)
4627: ooo-------
Parent 4627 - L-Child died 4628 = 0x0000
49 49 595
Parent 4625 - R-Child died 4627 = 0x0000
Parent 4625 - waiting for L-Child (4626)
4625: ooo-------
Parent 4625 - L-Child died 4626 = 0x0000
$
空行是我按回车键的地方,为 cat
提供一些输入命令。如果你仔细观察的话你会看到,cat
PID 为 4629;当它退出时,它的状态为 0x000D,这表明它死于 SIGPIPE 信号 (13)。
在此示例运行中,原始 shell 的 PID 为 4625。它创建一个具有文件描述符 3 和 4 的管道,然后创建 4626 作为左子节点,4627 作为右子节点。 PID 4627 创建一个管道(也在文件描述符 3 和 4 上;其他已关闭和/或重定向到标准输入)并运行 4628 和 4629,其中 ls
和cat
(4626 变为 wc
)。 4627 你有父进程等待退出;您有 4627 正在等待 4629 ( cat
);因此,在您输入 cat
之前,不会发生任何事情。 .
当您输入 cat
时,由于管道关闭而退出; 4629 由 4627 收集,然后 4627 也继续收集 4628 ( ls
)。现在 4625 开始收集 4627,然后是 4626,然后自身终止。
这棵树有点奇怪,因为它是用管道中最左边的进程 ( cat
) 作为树中最右边的进程来设置的。
通常,管道的状态是管道中最后一个进程的状态。与bash
,您还可以获取管道中其他进程的退出状态,因此主 shell 必须启动管道中的所有进程(以便这些进程是其子进程,并且可以等待它们并收集退出状态)。
无论这是否是您真正想要的,代码似乎都是根据实现的设计运行的。
更常见的是,您不会等待特定进程死亡,而是等待任何子进程死亡,然后相应地清理数据结构。但管道在 cat
之前尚未完成是因为你有一个进程专门等待 cat
.
我不确定您想如何解决这个问题。正如评论中所指出的,我倾向于将其结构更像 C Minishell Adding Pipelines 中的代码。 。然而,当管道中的第一个进程从终端读取时(例如 cat | ls | wc
),该代码的行为对我来说很奇怪,给我一个 I/O 错误。我还没有设法调试为什么!我确实知道,如果我将输入通过管道传输到其中,或者如果我使用 <<<
重定向它, ,效果很好。我不明白我收到的错误(至少可以说,这很令人厌烦)。
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define PIPE 1
#define CMD 2
typedef struct s_tree
{
char *cmd;
char type;
struct s_tree *left;
struct s_tree *right;
} t_tree;
enum { DESCRIPTORS_PER_LINE = 64 };
static void open_fds(int max_fd)
{
int fd;
struct stat buff;
fprintf(stderr, "%d: ", (int)getpid());
for (fd = 0; fd < max_fd; fd++)
{
if (fstat(fd, &buff) < 0)
putc('-', stderr);
else
putc('o', stderr);
if (fd % DESCRIPTORS_PER_LINE == DESCRIPTORS_PER_LINE - 1)
putc('\n', stderr);
}
if (fd % DESCRIPTORS_PER_LINE != 0)
putc('\n', stderr);
}
static void my_exit(int value)
{
fprintf(stderr, "EXITING %d\n", value);
perror(NULL);
exit(value);
}
static void dump_node(t_tree *tree)
{
assert(tree != 0);
fprintf(stderr, "%d: Node type %d\n", (int)getpid(), tree->type);
if (tree->cmd != 0)
fprintf(stderr, "%d: Command: %s\n", (int)getpid(), tree->cmd);
fprintf(stderr, "%d: Left: 0x%.12" PRIXPTR ", Right: 0x%.12" PRIXPTR "\n",
(int)getpid(), (uintptr_t)tree->left, (uintptr_t)tree->right);
}
static int execute_cmd(t_tree *tree)
{
//usleep((10 + rand() % 100) * 1000);
assert(tree->type == CMD);
dump_node(tree);
fprintf(stderr, "%d: Command: %s\n", (int)getpid(), tree->cmd);
open_fds(10);
execlp(tree->cmd, tree->cmd, NULL);
fprintf(stderr, "%d: Exec fail (%s)\n", (int)getpid(), tree->cmd);
my_exit(102);
return(-1);
}
static int execute_tree(t_tree *tree)
{
int statusleft;
int statusright;
pid_t pidright;
pid_t pidleft;
int fd[2];
assert(tree->type == PIPE);
dump_node(tree);
if (pipe(fd) < 0)
my_exit(1);
fprintf(stderr, "%d: Pipe: r %d, w %d\n", (int)getpid(), fd[0], fd[1]);
if ((pidleft = fork()) < 0)
my_exit(2);
if (pidleft == 0)
{
fprintf(stderr, "%d: L-Child\n", (int)getpid());
open_fds(10);
fflush(0);
if (close(fd[1]) < 0)
my_exit(3);
if (dup2(fd[0], 0) < 0)
my_exit(4);
close(fd[0]);
if (tree->left->type == PIPE)
return(execute_tree(tree->left));
else if (tree->left->type == CMD)
return(execute_cmd(tree->left));
else
my_exit(100);
}
else
{
if (tree->right != NULL)
{
if ((pidright = fork()) < 0)
my_exit(5);
if (close(fd[0]) < 0)
my_exit(6);
if (pidright == 0)
{
fprintf(stderr, "%d: R-Child\n", (int)getpid());
open_fds(10);
if (dup2(fd[1], 1) < 0)
my_exit(7);
close(fd[1]);
if (tree->right->type == PIPE)
return(execute_tree(tree->right));
else if (tree->right->type == CMD)
return(execute_cmd(tree->right));
else
my_exit(101);
}
else
{
fprintf(stderr, "Parent %d - waiting for R-Child (%d)\n", (int)getpid(), pidright);
open_fds(10);
if (close(fd[1]) < 0)
my_exit(8);
if (waitpid(pidright, &statusright, 0) < 0)
my_exit(9);
fprintf(stderr, "Parent %d - R-Child died %d = 0x%.4X\n",
(int)getpid(), pidright, statusright);
}
}
fprintf(stderr, "Parent %d - waiting for L-Child (%d)\n", (int)getpid(), pidleft);
open_fds(10);
if (waitpid(pidleft, &statusleft, 0) < 0)
my_exit(10);
fprintf(stderr, "Parent %d - L-Child died %d = 0x%.4X\n",
(int)getpid(), pidleft, statusleft);
}
return(0);
}
/*
** Pipes at RHS to avoid issues with slaash, backslash, newline, start
** being a comment start symbol
**
** PIPE |
** /\ |
** / \ |
** / \ |
** wc PIPE |
** /\ |
** / \ |
** / \ |
** ls cat |
**
** cat | ls | wc
*/
int main(void)
{
t_tree *tree;
setvbuf(stderr, 0, _IOLBF, BUFSIZ);
printf("%d: Main shell\n", (int)getpid());
tree = malloc(sizeof(*tree));
tree->left = malloc(sizeof(*tree));
tree->right = malloc(sizeof(*tree));
tree->right->left = malloc(sizeof(*tree));
tree->right->right = malloc(sizeof(*tree));
tree->type = PIPE;
tree->left->right = NULL;
tree->left->left = NULL;
tree->left->type = CMD;
tree->left->cmd = malloc(strlen("/usr/bin/wc") + 1);
strcpy(tree->left->cmd, "/usr/bin/wc");
tree->right->type = PIPE;
tree->right->left->right = NULL;
tree->right->left->left = NULL;
tree->right->left->type = CMD;
tree->right->left->cmd = malloc(strlen("/bin/ls") + 1);
strcpy(tree->right->left->cmd, "/bin/ls");
tree->right->right->left = NULL;
tree->right->right->left = NULL;
tree->right->right->type = CMD;
tree->right->right->cmd = malloc(strlen("/bin/cat") + 1);
strcpy(tree->right->right->cmd, "/bin/cat");
//tree->parent = NULL;
//tree->left->parent = tree;
//tree->right->parent = tree;
//tree->right->left->parent = tree->right;
//tree->right->right->parent = tree->right;
return(execute_tree(tree));
}
关于c - 具有文件描述符限制的多管道实现无法正常工作。 (壳),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19070890/
我通过 spring ioc 编写了一些 Rest 应用程序。但我无法解决这个问题。这是我的异常(exception): org.springframework.beans.factory.BeanC
我对 TestNG、Spring 框架等完全陌生,我正在尝试使用注释 @Value通过 @Configuration 访问配置文件注释。 我在这里想要实现的目标是让控制台从配置文件中写出“hi”,通过
为此工作了几个小时。我完全被难住了。 这是 CS113 的实验室。 如果用户在程序(二进制计算器)结束时选择继续,我们需要使用 goto 语句来到达程序的顶部。 但是,我们还需要释放所有分配的内存。
我正在尝试使用 ffmpeg 库构建一个小的 C 程序。但是我什至无法使用 avformat_open_input() 打开音频文件设置检查错误代码的函数后,我得到以下输出: Error code:
使用 Spring Initializer 创建一个简单的 Spring boot。我只在可用选项下选择 DevTools。 创建项目后,无需对其进行任何更改,即可正常运行程序。 现在,当我尝试在项目
所以我只是在 Mac OS X 中通过 brew 安装了 qt。但是它无法链接它。当我尝试运行 brew link qt 或 brew link --overwrite qt 我得到以下信息: ton
我在提交和 pull 时遇到了问题:在提交的 IDE 中,我看到: warning not all local changes may be shown due to an error: unable
我跑 man gcc | grep "-L" 我明白了 Usage: grep [OPTION]... PATTERN [FILE]... Try `grep --help' for more inf
我有一段代码,旨在接收任何 URL 并将其从网络上撕下来。到目前为止,它运行良好,直到有人给了它这个 URL: http://www.aspensurgical.com/static/images/a
在过去的 5 个小时里,我一直在尝试在我的服务器上设置 WireGuard,但在完成所有设置后,我无法 ping IP 或解析域。 下面是服务器配置 [Interface] Address = 10.
我正在尝试在 GitLab 中 fork 我的一个私有(private)项目,但是当我按下 fork 按钮时,我会收到以下信息: No available namespaces to fork the
我这里遇到了一些问题。我是 node.js 和 Rest API 的新手,但我正在尝试自学。我制作了 REST API,使用 MongoDB 与我的数据库进行通信,我使用 Postman 来测试我的路
下面的代码在控制台中给出以下消息: Uncaught DOMException: Failed to execute 'appendChild' on 'Node': The new child el
我正在尝试调用一个新端点来显示数据,我意识到在上一组有效的数据中,它在数据周围用一对额外的“[]”括号进行控制台,我认为这就是问题是,而新端点不会以我使用数据的方式产生它! 这是 NgFor 失败的原
我正在尝试将我的 Symfony2 应用程序部署到我的 Azure Web 应用程序,但遇到了一些麻烦。 推送到远程时,我在终端中收到以下消息 remote: Updating branch 'mas
Minikube已启动并正在运行,没有任何错误,但是我无法 curl IP。我在这里遵循:https://docs.traefik.io/user-guide/kubernetes/,似乎没有提到关闭
每当我尝试docker组成任何项目时,都会出现以下错误。 我尝试过有和没有sudo 我在这台机器上只有这个问题。我可以在Mac和Amazon WorkSpace上运行相同的容器。 (myslabs)
我正在尝试 pip install stanza 并收到此消息: ERROR: No matching distribution found for torch>=1.3.0 (from stanza
DNS 解析看起来不错,但我无法 ping 我的服务。可能是什么原因? 来自集群中的另一个 Pod: $ ping backend PING backend.default.svc.cluster.l
我正在使用Hibernate 4 + Spring MVC 4当我开始 Apache Tomcat Server 8我收到此错误: Error creating bean with name 'wel
我是一名优秀的程序员,十分优秀!