支撑管道(有用的Hello World)

时间:2010-12-27 23:18:07

标签: c++ unix command-line pipe stdin

我正在尝试编写一系列遵循基本Unix哲学的简单C ++程序:

  1. 让每个程序做好一件事。
  2. 期望每个节目的输出成为另一个尚未知的节目的输入。
  3. 我遇到了一个问题,试图让一个的输出成为另一个的输入,并且获得一个的输出是其自身的单独实例的输入。非常简单,我有一个程序添加,它接受参数并吐出总和。我希望能够将输出传输到另一个添加实例。

    ./add 1 2 | ./add 3 4
    

    应该产生 10 但目前产生 7

    我遇到了两个问题:

    1. cin 等待来自控制台的用户输入。我不希望这样,并且无法找到一个简单的示例,显示使用标准输入流而不在控制台中查询用户。如果有人知道一个例子,请告诉我。
    2. 我无法弄清楚如何在支持管道时使用标准输入。目前,它似乎不起作用。如果我发出命令 ./ add 1 2 | ./add 3 4 导致7。
    3. 相关代码如下:

      add.cpp代码段

      // ... COMMAND LINE PROCESSING ...
          std::vector<double> numbers = multi.getValue(); // using TCLAP for command line parsing
      
          if (numbers.size() > 0)
          {
          double sum = numbers[0];
      
          double arg;
          for (int i=1; i < numbers.size(); i++)
          {
            arg = numbers[i];
      
            sum += arg;
          }
      
          std::cout << sum << std::endl;
        }
        else
        {
            double input;
            // right now this is test code while I try and get standard input streaming working as expected
            while (std::cin)
            {
                  std::cin >> input;
      
                  std::cout << input << std::endl;
            }
      
          }
      // ... MORE IRRELEVANT CODE ...
      

      所以,我想我的问题是,是否有人看到这段代码的错误是为了支持管道标准输入?是否有一些众所周知(或隐藏)的资源可以清楚地解释如何实现支持basic Unix philosophy的示例应用程序?

      @Chris Lutz 我已将代码更改为以下内容。 cin 仍然在控制台上等待用户输入的问题,并且不仅仅取自管道传递的标准输入。我错过了处理这件事的微不足道的事吗?我还没有尝试过Greg Hewgill的回答,但是看不出这会有什么帮助,因为问题仍然是 cin

      // ... COMMAND LINE PROCESSING ...
          std::vector<double> numbers = multi.getValue(); // using TCLAP for command line parsing
      
          double sum = numbers[0];
      
          double arg;
          for (int i=1; i < numbers.size(); i++)
          {
            arg = numbers[i];
      
            sum += arg;
          }
      
          // right now this is test code while I try and get standard input streaming working as expected
          while (std::cin)
          {
                std::cin >> arg;
      
                std::cout << arg << std::endl;
          }
      
          std::cout << sum << std::endl;
      // ... MORE IRRELEVANT CODE ...
      

      编辑:几乎在那里,这允许输出通过管道连接到输入,但是看起来它正在重复输出。我正在发出 ./ add 1 2 | ./add 3 4 并获得 13 。在while循环中使用一些额外的 cout 语句,我可以看到来自 cin 的两个 3 值只有一个 cout 语句。我为什么要复制一份?

      // ... COMMAND LINE PROCESSING ...
          std::vector<double> numbers = multi.getValue(); // using TCLAP for command line parsing
      
          double sum = numbers[0];
      
          double arg;
          for (int i=1; i < numbers.size(); i++)
          {
            arg = numbers[i];
      
            sum += arg;
          }
      
          if (!isatty(fileno(stdin)))
          {
            while (std::cin)
            {
                std::cin >> arg; // this may require the use of std::strtod(), but to simplify the example I'm keeping it as this.
      
                sum += arg;
            }
          }
      
          std::cout << sum << std::endl;
      // ... MORE IRRELEVANT CODE ...
      

3 个答案:

答案 0 :(得分:4)

问题可能在这里:

if (numbers.size() > 0)

如果您有任何参数,它会添加它们并忽略所有管道数据。所以当然./add 3返回3 - 它有一个参数,所以它忽略了管道数据。

你应该修改你的代码来添加两个输入(如果给出输入)和参数,而不是 - 或者。请记住:命令行参数不排除管道输入。

答案 1 :(得分:2)

您可能会觉得有用的一个函数是isatty(),它告诉您文件描述符是否连接到交互式会话。您可以这样使用它:

if (!isatty(fileno(stdin))) {
    while (std::cin) {
        // ...
    }
}

如果不是交互式(意味着stdin从文件或管道重定向),这只会尝试从终端读取输入。

答案 2 :(得分:1)

我想说最简单的是忽略程序中stdin的阅读。相反,只让程序从参数中读取,并调用它:./add 1 2 | xargs ./add 3 4

xargs会将第一个add参数的输出设为第二个add