我的程序是一个常见的shell,我试图用C ++编写。除了从命令行获取命令外,它还必须能够读取文件中的命令 - 文件名作为可选的arg传递,而不是通过重定向传递。
如果arg存在,我打开传递的文件名,否则打开“/ dev / stdin”。打开开发文件我并不高兴,这不是我的主要问题,但如果有人有更好的方法,我很乐意听到它。
最终我必须读取给shell的命令,但首先我必须提示我是从stdin读取的提示还是如果输入来自文件则跳过提示。我的问题是:有没有更好的方法来确定getCommand
输入流是否是标准输入,而不是声明全局或传递布尔或类似的黑客攻击?
我觉得如果我能以某种方式使用std :: cin而不是打开/ dev文件,我可以将流作为istream
传递。这会更容易区分这两者吗?例如。 if (source == cin)
?
感谢您提出的所有建议。
bool getCommand(ifstream source, std::string command)
{
if (source == stdin)
//print prompt to stdout
// do the rest of stuff
return true;
}
int main(int argc, char *argv[])
{
std::ifstream input;
std::string command;
if (argc == 2)
{
input.open(argv[1], std::ifstream::in);
if (! input)
{
perror("input command file stream open");
exit(EXIT_FAILURE);
}
}
else
{
input.open("/dev/stdin", std::ifstream::in);
if (! input)
{
perror("input stdin stream open");
exit(EXIT_FAILURE);
}
}
//.......
if (getCommand(input, command))
//.......
}
答案 0 :(得分:3)
如果您使用std::istream&
作为变量的类型,那么您可以使用std::cin
代替打开/dev/stdin
:
std::ifstream fileinput;
if (argc == 2)
{
fileinput.open(argv[1], std::ifstream::in);
if (! fileinput)
{
perror("input command file stream open");
exit(EXIT_FAILURE);
}
}
std::istream &input = (argc == 2) ? fileinput : std::cin;
你的问题的其余部分应该是关于识别tty(Detect if stdin is a terminal or pipe?)。但如果做不到这一点,一旦你做了上述改动,就可以与std::cin
的地址进行比较:
if (&input == &std::cin) {
std::cout << "prompt:";
}
显然,这不会识别命令行参数为/dev/stdin
的情况,因此它有点像躲避。但我可能会认为,鉴于有趣的要求,这实际上是一种改进,因为有人至少可以写yourprogram /dev/stdin < input.txt
或sort input.txt | yourprogram /dev/stdin
来解决你的限制并避免提示: - )
答案 1 :(得分:2)
首先,如果您想要从std::cin
或std::ifstream
阅读,我会根据std::istream
来实施这项工作,当然要避免打开/dev/stdin
:
std::istream in(std::cin.rdbuf());
std::ifstream fin;
if (argc == 2) {
fin.open(av[1]);
// check that the file is actually open or produce an error
in.rdbuf(fin.rdbuf());
}
else {
// determine if you need to create a prompt
}
if (getCommand(in, command)) {
...
}
现在,要确定您是否确实需要编写提示,仅确定是否正在读取标准输入,还需要确定标准输入是否连接到具有屏幕和键盘的内容。但是,没有可移植的方法。在UNIX上有像isatty()
这样的函数,可用于确定文件描述符0是否连接到tty。我会使用此信息来设置iword()
,然后可以使用它来检查流是否需要提示:
static int const needs_prompt = std::ios_base::xalloc();
...
in.iword(needs_prompt) = isatty(0);
...
if (in.iword(needs_prompt)) {
std::cout << "pompt>";
}
如果您想获得幻想,可以创建一个自定义std::streambuf
,它与std::ostream
连接,tie()
输入流流,并在{{{}}上写一个提示1}}:每次对输入流执行读取操作时,都会刷新sync()
ed tie()
。但是,这要求您只为每个生成的提示读取一次,例如使用std::ostream
。显然,如果您不需要提示,则不要std::getline(in, line)
tie()
。下面是一个简单的程序,演示了自动提示方法(没有做任何其他业务):
std::ostream