管道末端的重定向(C壳) [英] Redirection at the end of the pipe (C shell)

查看:93
本文介绍了管道末端的重定向(C壳)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作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.

  1. 关闭管道的读取端:此过程只会写入管道.
  2. dup2()STDOUT的管道的写入结束:正在将该过程写入STDOUT的内容写入管道.
  3. 执行覆盖:exec()ls.
  1. Close the reading end of the pipe: this process will only write to the pipe.
  2. dup2() the writing end of the pipe to STDOUT: what this process writes to STDOUT is being written to the pipe.
  3. Perform the overlay: exec() with ls.

tr的过程:

Process for tr:

  1. 关闭管道的写入端:此过程仅从管道中读取.
  2. dup2()STDIN的管道的读取端:该过程从STDIN读取的内容来自管道.
  3. 为了对text.txt文件执行重定向,首先open()要写入的文件text.txt并带有标志O_CREATO_TRUNC,然后dup2()获得的文件描述符到STDOUT.

  1. Close the writing end of the pipe: this process will only read from the pipe.
  2. dup2() the reading end of the pipe to STDIN: what this process reads from STDIN is coming from the pipe.
  3. In order to perform the redirection to the text.txt file, first open() the file text.txt for writing and with the flags O_CREAT and O_TRUNC, then dup2() the obtained file descriptor to STDOUT.

使用叠加层: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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆