问题描述
我正在尝试执行 ls |wc -l
通过 C 中的程序,而不是使用命令行.这是我当前的工作代码:
I'm trying to execute ls | wc -l
through a program in C, instead of using the command line.This is my current working code:
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 循环?
How would I rewrite this code to work with a for-loop?
例如:
for (i=0; i<2; i++) {
// Rewrite the 2-level pipe here
}
稍后,我想扩展 for 循环以执行更多的进程,例如 a |乙 |c |...代码>
Later, I would like to extend the for loop to execute more processes piped together like a | b | c | ...
推荐答案
为了将多个命令连接在一起,您需要保持父级运行以保持每个命令的 fork()
ing.
In order to pipe multiple commands together, you'll need to keep the parent running to keep fork()
ing for each command.
使用 for
循环,您需要对第一个 n - 1
命令执行此操作(最后一个将在主程序中执行):
Using a for
loop, you will need to do this for the first n - 1
commands (the last one will be executed in the main program):
- 创建管道.
- 执行
fork()
. - 在孩子中:用上一个管道的读端覆盖标准输入,用当前管道的写端覆盖标准输出.
- 在子进程中:执行
execve()
. - 在父级中:关闭不需要的管道并保存当前管道的读取端以用于下一次迭代.
- Create a pipe.
- Execute
fork()
. - In the child: overwrite standard input with the read end of the previous pipe, and standard output with the write end of the current pipe.
- In the child: execute
execve()
. - In the parent: close unneeded pipes and save read end of current pipe to be used in the next iteration.
然后,循环结束后,用最后一个管道的读取端覆盖标准输入,并执行最后一个命令的execve()
.
Then, after the loop ends, overwrite standard input with the read end of the last pipe and execute execve()
of the last command.
下面我写了一个简单的执行示例:
Below I've written a simple working example that executes:
ls | wc -l | xargs printf "0x%x
" | cowsay
它应该适用于任意数量的命令(包括仅 1 个单个命令).
It should work for any number of commands (including only 1 single command).
注意:为了简短起见,我没有在此代码中为 execvp()
添加错误检查,但您绝对应该在每次调用后检查错误pipe()
、dup2()
、fork()
和任何其他函数.
NOTE: I did not add error checks in this code apart for execvp()
just to make it short, but you should definitely check for errors after each call to pipe()
, dup2()
, fork()
and any other function.
代码:
#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
", 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 行):
Output on my machine (since ls
returned 41 == 0x29 lines):
______
< 0x29 >
------
^__^
(oo)\_______
(__) )/
||----w |
|| ||
这篇关于使用循环在 C 中管道两个或多个 shell 命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!