使用循环在 C 中管道两个或多个 shell 命令
Posted
技术标签:
【中文标题】使用循环在 C 中管道两个或多个 shell 命令【英文标题】:Pipe two or more shell commands in C using a loop 【发布时间】:2021-12-22 23:15:19 【问题描述】:我正在尝试通过 C 中的程序执行ls | wc -l
,而不是使用命令行。
这是我当前的工作代码:
int main()
int pfds[2];
pipe(pfds);
pid_t pid = fork();
if ( pid == 0 ) /* The child process*/
close(1);
dup(pfds[1]);
close(pfds[0]);
execlp("ls", "ls", NULL);
else /* The parent process*/
close(0);
dup(pfds[0]);
close(pfds[1]);
wait(0);
execlp("wc", "wc", "-l", NULL);
return 0;
如何重写此代码以使用 for 循环?
例如:
for (i=0; i<2; i++)
// Rewrite the 2-level pipe here
稍后,我想扩展 for 循环以执行更多进程,例如 a | b | c | ...
【问题讨论】:
您想使用for
循环运行ls | wc -l
N 次而不是一次(在您的示例2 中)?
对于简单的双命令管道没关系,您是否尝试为未知长度的更通用管道解决这个问题?
@MarcoBonelli 是的,我正在尝试解决这个问题以获得更通用的管道
@HMemon 我想你误解了我的问题。我在问您是否要多次运行完全相同的管道进程 (ls | wc -l
)。您想要那个,还是想要使用for
循环来执行更多 个进程,如a | b | c | ...
?不清楚你在问什么。您应该在问题中指定这一点。
@MarcoBonelli,我想使用 for 循环来执行更多的进程,就像 |乙 | c | ...
【参考方案1】:
为了将多个命令连接在一起,您需要让父级保持运行以保持每个命令的fork()
ing。
使用for
循环,您需要对第一个n - 1
命令执行此操作(最后一个将在主程序中执行):
-
创建管道。
执行
fork()
。
在子进程中:用上一个管道的读端覆盖标准输入,用当前管道的写端覆盖标准输出。
在孩子中:执行execve()
。
在父级中:关闭不需要的管道并保存当前管道的读取端以用于下一次迭代。
然后,循环结束后,用最后一个管道的读取端覆盖标准输入,并执行最后一个命令的execve()
。
下面我写了一个简单的执行示例:
ls | wc -l | xargs printf "0x%x\n" | cowsay
它应该适用于任意数量的命令(仅包括 1 个单一命令)。
注意:为了简短起见,我没有在此代码中为 execvp()
添加错误检查,但您绝对应该在每次调用 pipe()
、dup2()
后检查错误, fork()
和任何其他函数。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_ARGC 3
int main(void)
char *commands[][MAX_ARGC + 1] =
"ls", NULL,
"wc", "-l", NULL,
"xargs", "printf", "0x%x\n", NULL,
"cowsay", NULL
;
size_t i, n;
int prev_pipe, pfds[2];
n = sizeof(commands) / sizeof(*commands);
prev_pipe = STDIN_FILENO;
for (i = 0; i < n - 1; i++)
pipe(pfds);
if (fork() == 0)
// Redirect previous pipe to stdin
if (prev_pipe != STDIN_FILENO)
dup2(prev_pipe, STDIN_FILENO);
close(prev_pipe);
// Redirect stdout to current pipe
dup2(pfds[1], STDOUT_FILENO);
close(pfds[1]);
// Start command
execvp(commands[i][0], commands[i]);
perror("execvp failed");
exit(1);
// Close read end of previous pipe (not needed in the parent)
close(prev_pipe);
// Close write end of current pipe (not needed in the parent)
close(pfds[1]);
// Save read end of current pipe to use in next iteration
prev_pipe = pfds[0];
// Get stdin from last pipe
if (prev_pipe != STDIN_FILENO)
dup2(prev_pipe, STDIN_FILENO);
close(prev_pipe);
// Start last command
execvp(commands[i][0], commands[i]);
perror("execvp failed");
exit(1);
我机器上的输出(因为 ls
返回 41 == 0x29 行):
______
< 0x29 >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
【讨论】:
以上是关于使用循环在 C 中管道两个或多个 shell 命令的主要内容,如果未能解决你的问题,请参考以下文章