Поддерживающий трубопровод (полезный Hello World) - PullRequest
4 голосов
/ 28 декабря 2010

Я пытаюсь написать набор простых программ на C ++, которые следуют базовой философии Unix:

  1. Заставьте каждую программу хорошо выполнять одну вещь.
  2. Ожидайте, что выходные данные каждой программы станут входными данными для другой, пока неизвестной программы.

У меня возникла проблема с попыткой получить выходные данные одного из них для ввода другого, а выходные данные одного из них - для ввода отдельного экземпляра самого себя. Вкратце, у меня есть программа add , которая принимает аргументы и выдает суммирование. Я хочу иметь возможность передавать вывод в другой добавить экземпляр.

./add 1 2 | ./add 3 4

Что должно давать 10 , но в настоящее время дает 7 .

Я столкнулся с двумя проблемами:

  1. cin ожидает ввода пользователя с консоли. Я не хочу этого, и не смог найти простой пример, показывающий использование стандартного потока ввода без запроса пользователя в консоли. Если кто-то знает пример, пожалуйста, дайте мне знать.
  2. Я не могу понять, как использовать стандартный ввод при поддержке трубопроводов. В настоящее время, похоже, это не работает. Если я введу команду . / Add 1 2 | ./add 3 4 это приводит к 7.

Соответствующий код ниже:

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 ...

Итак, я думаю, мой вопрос (-ы): кто-нибудь видит, что не так с этим кодом, чтобы поддерживать стандартный ввод данных? Существуют ли хорошо известные (или скрытые) ресурсы, в которых четко объясняется, как реализовать пример приложения, поддерживающего базовую философию Unix ?

@ Крис Латс Я изменил код на то, что ниже. Проблема в том, что cin все еще ожидает пользовательского ввода на консоли, а не просто берет от стандартного ввода, переданного из канала. Я что-то упустил тривиально для обработки этого? Я еще не пробовал ответить Грегу Хьюгиллу, но не понимаю, как это могло бы помочь, поскольку проблема все еще с 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 . С некоторыми дополнительными операторами cout в цикле while я вижу два значения 3 , поступающих из cin , когда у меня только один 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 ]

4 голосов
/ 28 декабря 2010

Возможно, проблема здесь:

if (numbers.size() > 0)

Если у вас есть аргументы, он добавляет их и игнорирует все передаваемые данные. Поэтому, конечно, ./add 3 возвращает 3 - у него есть аргумент, поэтому он игнорирует переданные данные.

Вы должны исправить свой код, добавив и input (если он задан) и аргументы, а не или-или. Помните: аргументы командной строки не исключают ввод по конвейеру.

2 голосов
/ 28 декабря 2010

Одна функция, которая может оказаться полезной, - isatty(), которая сообщает вам, подключен ли дескриптор файла к интерактивному сеансу или нет.Вы можете использовать его следующим образом:

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

Он будет пытаться считывать ввод с терминала, только если он не интерактивный (то есть stdin перенаправляется из файла или канала).

1 голос
/ 28 декабря 2010

Я бы сказал, что проще всего игнорировать чтение из stdin в вашей программе.Вместо этого, позвольте программе только читать из аргументов и вызывать ее так: ./add 1 2 | xargs ./add 3 4

xargs сделает вывод из первого add аргумента вторым add.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...