始终输出到屏幕并允许重定向
Always output to screen and allow redirection
我正在编写一个小的 CLI 应用程序,我想允许用户重定向到文件,而标准 cout 语句转到输出.txt我希望进度始终进入屏幕。
./myApp > output.txt
10% complete
...
90% complete
Completed
这可能吗? 我该怎么做?
提前感谢!!
即使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++库的某些实现提供了用于此目的的扩展。看这里。
或者,如果您不关心可靠地获取错误代码,则可以std::ofstream terminal("/dev/tty")
.
此外,如果您这样做,作为设计考虑因素,提供一个安静的选项来让用户关闭对终端的写入是一个好主意。
您的进程无法知道 shell 是否重定向标准控制台输出 (std::cout
(。
因此,您需要另一个句柄,该句柄可让您独立于该重定向输出到终端。
正如@Mark在他们的评论中提到的,您可以 (ab-( 使用1std::cerr
来做到这一点,以及一些 ASCII 技巧来覆盖终端上的当前输出行(查看退格字符:'b'
(。
1( 更不用说如果输出实际上没有重定向,则在终端打印的混乱。
您可以将进度指示器写入stderr
流。 如果用户将stdout
重定向到文件,它们将显示在控制台上。
例如:
fprintf(stderr, "10%% completen");
我想出了该怎么做,即使用户重定向stderr
.以下代码获取当前终端的名称,并检查我们的输出是否被重定向。它还具有my_write((函数,允许您同时写入终端和重定向文件,如果它们已重定向stdout
。您可以将 my_write(( 函数与writetoterm
变量一起使用,无论您想在哪里写入您希望始终写入终端的内容。extern "C"
必须在那里,否则(无论如何,在带有 GCC 6.3 的 Debian 9 上(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;
}
我找到了官方的std::处理这个问题的方法。 还有另一种类型...标准::堵塞。 这是专门用于信息,并且始终显示在命令行上,即使用户将程序myProgram的输出重定向>出来.txt。
谢谢,很高兴看到可以完成的所有方法。
- 如何将stdout重定向到stderr
- 编写时C++中的输入重定向问题
- 获取通过重定向传入的输入文件的名称?
- Windows C++重定向库
- 写入文件 a.txt,而终端重定向到文件 b.txt
- 使用 dup2() 进行输入重定向
- 将 clangd stderr 重定向到文件而不是控制台
- 如何在C++中获取重定向网页的URL
- 将标准输出重定向到ostream
- 如何撤消此代码上的 cin 重定向?
- 使用重定向标准处理子进程中的 kbhit
- 是否可以将子进程的 stdout 重定向到父进程中的另一个文件?
- 重定向输入和输出时如何处理主文件I/O?
- 如何将HTTPS流量重定向到本地主机:443上的代理?
- 使用重定向命令从 stdin 读入的字符串"<"输入文件未正确附加
- 尝试在 Windows 上重定向 stdout 和 stderr——_fileno(stdout) 返回 -2
- 可以将Boost消息队列文件重定向到用户指定的位置
- 始终输出到屏幕并允许重定向
- 正在将控制台输出重定向到同一解决方案中的MFC屏幕输出
- 即使重定向了标准输出和标准错误,Unix程序如何在屏幕上显示输出?