管道末端的重定向(C壳) [英] Redirection at the end of the pipe (C shell)
问题描述
我正在尝试制作ls | tr a b > text.txt
我已经完成了管道,但是无法将STDOUT添加到管道的末尾(在我的情况下,STDOUT只能在最后一个参数中使用)
I'm trying to make ls | tr a b > text.txt
I have piping done, but I can't add STDOUT to the end of the pipe (STDOUT in my case can be only in the last argument)
我标记了代码的一部分,应该在其中进行重定向,我认为应该打开文件,并使用dup2
方法,但是我不知道该用哪种方式
I mark the part of the code, in which redirection should be done, I think that file should be opened, and dup2
method used, but I don't know in which way
方法包含管道-
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]);
}
编辑 在我写的///标记的地方
EDIT in the marked by /// place I wrote
pipe(fd);
int out = open(cmd[n-1][0],O_WRONLY|O_CREAT|O_TRUNC);
spawn_proc(in, out, cmd[i]);
close(fd[1]);
推荐答案
我认为应该打开文件,并使用
dup2
方法,但是我不知道用哪种方式
I think that file should be opened, and
dup2
method used, but I don't know in which way
您对实现重定向的机制是正确的.应该在打算用于tr
的过程中执行此操作,然后再执行覆盖.
You are right about the mechanisms for implementing the redirection. It should be done on the process intended for tr
, and before performing the overlay.
让我们一步一步走
ls | tr a b > text.txt
首先创建一个管道,然后创建fork()
.
First create a pipe, then fork()
.
从现在开始,有两个进程并行运行,它们最终都将通过exec()
进行覆盖:一个使用ls
程序,另一个使用tr
程序.
From now on, there are two processes running in parallel, both of them will be eventually overlaid by means of exec()
: one with the ls
program, the other with the tr
program.
- 关闭管道的读取端:此过程只会写入管道.
-
dup2()
到STDOUT
的管道的写入结束:正在将该过程写入STDOUT
的内容写入管道. - 执行覆盖:
exec()
和ls
.
- Close the reading end of the pipe: this process will only write to the pipe.
dup2()
the writing end of the pipe toSTDOUT
: what this process writes toSTDOUT
is being written to the pipe.- Perform the overlay:
exec()
withls
.
tr
的过程:
Process for tr
:
- 关闭管道的写入端:此过程仅从管道中读取.
-
dup2()
到STDIN
的管道的读取端:该过程从STDIN
读取的内容来自管道. -
为了对
text.txt
文件执行重定向,首先open()
要写入的文件text.txt
并带有标志O_CREAT
和O_TRUNC
,然后dup2()
获得的文件描述符到STDOUT
.
- Close the writing end of the pipe: this process will only read from the pipe.
dup2()
the reading end of the pipe toSTDIN
: what this process reads fromSTDIN
is coming from the pipe.In order to perform the redirection to the
text.txt
file, firstopen()
the filetext.txt
for writing and with the flagsO_CREAT
andO_TRUNC
, thendup2()
the obtained file descriptor toSTDOUT
.
使用叠加层:exec()
和tr
.
请注意,如果命令是追加到text.txt
而不是被截断(即:使用>>
而不是>
):
Note that, if the command were appending to text.txt
instead of truncating it (i.e.: using >>
instead of >
):
ls | tr a b >> text.txt
在open()
编写text.txt
文件时,您将必须使用标志O_APPEND
而不是O_TRUNC
.
You would have to use the flag O_APPEND
instead of O_TRUNC
when open()
ing the text.txt
file.
我已经修改了您的代码(也是fork_pipes()
的界面).这是一个运行的最小示例,希望对您有所帮助.
I've modified your code (also the interface of fork_pipes()
). It's a minimal example that runs, I hope it helps.
#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;
}
中已指出的.您只需要在示例中调用一次pipe()
:对于每个管道运算符,只需一次一次调用pipe()
系统调用(即:|
字符)在复合命令中找到.例如,在以下命令中:
As already pointed out in this comment. You just need to call pipe()
once in your example: The pipe()
system call only needs to be called once for each pipe operator (i.e.: the |
character) found in the compound command. For example, in the following command:
cmd1 | cmd2 | cmd3 | cmd4
pipe()
必须被精确调用四次,因为有四个管道运算符.
pipe()
must be called exactly four times, since there are four pipe operators.
这篇关于管道末端的重定向(C壳)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!