我正在尝试编写一系列遵循基本Unix哲学的简单C ++程序:
我遇到了一个问题,试图让一个的输出成为另一个的输入,并且获得一个的输出是其自身的单独实例的输入。非常简单,我有一个程序添加,它接受参数并吐出总和。我希望能够将输出传输到另一个添加实例。
./add 1 2 | ./add 3 4
应该产生 10 但目前产生 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 ...
所以,我想我的问题是,是否有人看到这段代码的错误是为了支持管道标准输入?是否有一些众所周知(或隐藏)的资源可以清楚地解释如何实现支持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 ...
答案 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
。