我正在尝试制作ls | tr a b > text.txt
我已经完成管道,但无法将 STDOUT 添加到管道的末尾(在我的情况下,STDOUT 只能在最后一个参数中)
我标记了代码中应该进行重定向的部分,我认为应该打开该文件,并使用dup2
方法,但我不知道以哪种方式
方法包含管道 -
enum reqType { PIPE, STDOUT };
int spawn_proc (int in, int out, char** cmd) {
pid_t pid;
if ((pid = fork ()) == 0) {
if (in != 0) {
dup2 (in, 0);
close (in);
}
if (out != 1) {
dup2 (out, 1);
close (out);
}
return execvp (cmd[0], cmd);
}
return pid;
}
void fork_pipes (int n, char** cmd[], enum reqType type) {
int i;
pid_t pid;
int in, fd [2];
in = 0;
for (i = 0; i < n - 1; ++i) {
if(type == PIPE || i < n-2) {
pipe (fd);
spawn_proc (in, fd [1], cmd[i]);
close (fd [1]);
in = fd [0];
}
else if(type == STDOUT && i == n-2) {
///HOW TO IMPLEMENT THIS PART?
}
}
if (in != 0)
dup2 (in, 0);
execvp (cmd[i][0], cmd[i]);
}
编辑 在我写的///标记的地方
pipe(fd);
int out = open(cmd[n-1][0],O_WRONLY|O_CREAT|O_TRUNC);
spawn_proc(in, out, cmd[i]);
close(fd[1]);
最佳答案
I think that file should be opened, and
dup2
method used, but I don't know in which way
您关于实现重定向的机制是正确的。它应该在用于 tr
的进程上完成,并且在执行覆盖之前。
让我们一步一步来:
ls | tr a b > text.txt
首先创建一个管道,然后fork()
。
从现在开始,有两个个进程并行运行,它们最终将通过exec覆盖 ()
:一个使用 ls
程序,另一个使用 tr
程序。
ls
的流程:
- 关闭管道的读取端:此进程只会写入管道。
dup2()
管道到STDOUT
的写入结束:此进程写入STDOUT
的内容是正在写入管道。- 执行覆盖:
exec()
和ls
。
tr 的流程:
- 关闭管道的写入端:此进程只会从管道中读取。
dup2()
到STDIN
的管道的读取端:此进程从STDIN
读取的内容是来自管道。为了执行到
text.txt
文件的重定向,首先open()
文件text .txt
用于写入,并带有标志O_CREAT
和O_TRUNC
,然后dup2()
将获得的文件描述符发送到STDOUT
.执行覆盖:
exec()
和tr
。
请注意,如果命令附加到 text.txt
而不是截断它(即:使用 >>
而不是 >
) :
ls | tr a b >> text.txt
在 open()
text.txt
时,您必须使用标志 O_APPEND
而不是 O_TRUNC
> 文件。
代码片段
我修改了您的代码(还有fork_pipes()
的接口(interface))。这是一个运行的最小示例,我希望它有所帮助。
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int spawn_proc (int in, int out, char** cmd) {
pid_t pid;
if ((pid = fork ()) == 0) {
if (in != 0) {
dup2 (in, 0);
close (in);
}
if (out != 1) {
dup2 (out, 1);
close (out);
}
return execvp (cmd[0], cmd);
}
return pid;
}
void fork_pipes (char** cmd[], const char *redirection) {
int i, n;
int in, out, fd[2];
in = 0;
// obtain n from the NULL terminated cmd array
for (n = 0; cmd[n]; ++n)
;
// process all but the last elemet of the pipe
for (i = 0; i < n-1; ++i) {
pipe(fd);
spawn_proc(in, fd[1], cmd[i]);
close(fd [1]);
in = fd [0];
}
// process the last element of the pipe
if (redirection) {
out = open(redirection, O_WRONLY | O_CREAT | O_TRUNC);
fchmod(out, 0666);
} else
out = STDOUT_FILENO;
if (in != 0)
dup2(in, 0);
spawn_proc(in, out, cmd[i]);
}
int main()
{
char *cmd1[] = {"ls", NULL};
char *cmd2[] = {"tr", "a", "b", NULL};
char **cmd[] = { cmd1, cmd2, NULL};
// redirected to text.txt
fork_pipes(cmd, "text.txt");
// no redirection
fork_pipes(cmd, NULL);
// another example with a longer pipe
{
char *cmd1[] = {"echo", "hello world", NULL};
char *cmd2[] = {"tee", NULL};
char *cmd3[] = {"tee", NULL};
char *cmd4[] = {"tr", "lo", "10", NULL};
char **cmd[] = {cmd1, cmd2, cmd3, cmd4, NULL};
// redirected to redirection.txt
fork_pipes(cmd, "redirection.txt");
// no redirected
fork_pipes(cmd, NULL);
}
return 0;
}
正如 this comment 中已经指出的那样。您只需在示例中调用 pipe()
一次:pipe()
系统调用只需为每个调用一次>管道运算符(即:|
字符)在复合命令中找到。例如,在以下命令中:
cmd1 | cmd2 | cmd3 | cmd4
pipe()
必须恰好调用四次,因为有四个管道运算符。
关于c - 管道末端重定向(C shell),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47478392/