我正在编写一个小型CLI应用程序,我希望允许用户重定向到文件,而标准cout语句转到output.txt文件,我希望进展到屏幕。
./myApp > output.txt
10% complete
...
90% complete
Completed
这可能吗?我该怎么办?
提前致谢!!
答案 0 :(得分:1)
即使重定向 stdin 和 stdout ,这也会有效:
spectras@etherbee:~$ ./term
hello terminal!
spectras@etherbee:~$ ./term >/dev/null 2>&1
hello terminal!
这个想法是直接打开进程的控制终端,绕过任何重定向,如下所示:
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("/dev/tty", O_WRONLY);
if (fd < 0 && errno != ENODEV) {
/* something went wrong */
return 1;
}
int hasTTY = (fd >= 0);
if (hasTTY) {
write(fd, "hello terminal!\n", 16);
}
return 0;
}
来自man 4 tty
:
文件/ dev / tty是一个主编号为5的字符文件 次要编号0,通常为模式0666和owner.group root.tty。它是 进程控制终端的同义词,如果有的话。
如果您正在使用C ++,您可能希望将文件描述符包装到自定义streambuf中,因此您可以在其上使用常规流API。或者,C ++库的某些实现为此提供了扩展。见here。
或者,如果您不关心可靠地获取错误代码,则可以std::ofstream terminal("/dev/tty")
。
另外作为设计考虑,如果你这样做,提供一个安静的选项,让用户关闭写到终端是一个好主意。
答案 1 :(得分:0)
您的进程无法知道shell是否重定向标准控制台输出(None
)。
因此,您需要另一个句柄,让您可以独立于该重定向输出到终端。
正如their comment中提到的@Mark你可以(ab-)使用 1 std::cout
这样做,以及一些ASCII技巧来覆盖当前的输出行终端(查看退格字符:std::cerr
)。
1) 如果输出实际上没有被重定向,更不用说在终端上打印的混乱了。
答案 2 :(得分:0)
即使用户重定向stderr
,我也想出了如何做到这一点。以下代码获取当前终端的名称,并检查我们的输出是否被重定向。它还有一个my_write()函数,允许您写入终端和重定向文件,如果他们已重定向stdout
。您可以将my_write()函数与writetoterm
变量一起使用 - 您希望在哪里编写要将始终写入终端的内容。 extern "C"
有,否则(无论如何,在Debian 9上使用GCC 6.3)ttyname()
函数将一直返回NULL
。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <sstream>
using std::string;
using std::fstream;
using std::cout;
using std::endl;
using std::cerr;
using std::stringstream;
void my_write(bool writetoterm, int termfd, string data)
{
if(writetoterm)
{
int result = write(termfd, data.c_str(), data.length());
if(result < data.length()){
cerr << "Error writing data to tty" << endl;
}
}
cout << data;
}
extern "C" {
char* GetTTY(int fd){
//printf("%s", ttyname(fd));
return ttyname(fd);
}
}
int main(int argc, char** argv){
getenv("TTY");
bool writetoterm = false;
struct stat sb = {};
if(!GetTTY(STDOUT_FILENO)){
//not a TTY
writetoterm = true;
}
int ttyfd = open(GetTTY(2), O_WRONLY);
if(ttyfd < 0){
//error in opening
cout << strerror(errno) << endl;
}
string data = "Hello, world!\n";
my_write(true, ttyfd, data);
int num_for_cout = 42;
stringstream ss;
ss << "If you need to use cout to send something that's not a string" << endl;
ss << "Do this: " << num_for_cout << endl;
my_write(writetoterm, ttyfd, ss.str().c_str());
return 0;
}
答案 3 :(得分:0)
您可以将进度指示符编写到stderr
流。如果用户将stdout
重定向到文件,它们将出现在控制台上。
例如:
fprintf(stderr, "10%% complete\n");
答案 4 :(得分:0)
我找到了处理此问题的官方std ::方法。还有另一种类型...... std :: clog。这是专门针对信息的,并且总是出现在命令行中,即使用户重定向程序的输出myProgram&gt; out.txt。
非常感谢能够看到所有这些方法。