10

I have a Win32 application written in C that can have its console output via printf() redirected to a log file.

It would be nice if I could have my app. detect if it had been started with or without a redirect '>'.

Any ideas?

Michael Kohne
  • 11,888
  • 3
  • 47
  • 79
logout
  • 187
  • 3
  • 13
  • 2
    AFAIK, this isn't possible. So I'll be reading this to see if I'm wrong... – David Oneill Jan 18 '10 at 17:11
  • No way to know. I have seen programs that allow for a command line option to do different functionality which is often only turned on when the output is redirected. – Hogan Jan 18 '10 at 17:14
  • 1
    Not 100% sure in Windows, but in Linux there are many programs that behave differently if piped or not... the most common example is "ls". – fortran Jan 21 '10 at 11:14
  • Thanks fortran, I forgot to state that I'm coding for Windows. – logout Jan 21 '10 at 18:42
  • Possible duplicate of [How do I check if my Delphi console app is redirected to a file or pipe?](http://stackoverflow.com/questions/9021916/how-do-i-check-if-my-delphi-console-app-is-redirected-to-a-file-or-pipe) – Lol4t0 Nov 01 '15 at 19:01
  • @fortran: in fact, the "ls" program from GnuWin32 *does* behave differently if piped just like it does on Linux, so there's definitely a way to get that behavior. – dan04 May 27 '16 at 23:31

5 Answers5

5

Tom, thanks for the input.

I did some experiments and found this works for me..

fpost_t pos ;

fgetpos (stdout, & pos) ;

When an application's output is being redirected to a file, fgetpos() sets pos to zero. It makes sense since its freshly opened stderr for you.
EDIT: Actually, the value returned may be a positive integer if text has already been redirected to the log/file. So in your code you'd have something like if (pos >= 0) bfRedirected = TRUE;

When an application's output is not being redirected - it's going to the console device - not a file, so fgetpos() will set pos to -1.

phuclv
  • 37,963
  • 15
  • 156
  • 475
logout
  • 187
  • 3
  • 13
2

I think that pipes are blind by nature, so you don't have a built-in way to tell whether you're being redirected. Moreover, trying to find out what's happening behind an abstraction layer is a bad habit.

If you really need to control your output, add the log file name as a command line parameter!

That being said, you can make some smart guesswork to find out:

  • A program can query the shell command history to find out the most recent commands executed.
  • If you know the path to the logfiles, you can scan that directory and see if a file has been created or changed its size.
  • Benchmark writing speed when redirected and not redirected. This would work only if your system is ultra-stable, and environment condition won't change.
Adam Matan
  • 128,757
  • 147
  • 397
  • 562
1

Method from Microsoft: WriteConsole fails if it is used with a standard handle that is redirected to a file. If an application processes multilingual output that can be redirected, determine whether the output handle is a console handle (one method is to call the GetConsoleMode function and check whether it succeeds).

crea7or
  • 4,421
  • 2
  • 26
  • 37
0

AFAIK the answer to this is that you can't. Output redirection works by simply reading the stream of output from a given program and redirecting it to another pipe / stream. The design of file / streams is such that the writer is ignorant of the reader to the point that you shouldn't know you are being read.

Even detecting that there was a reader would be of no use because there is one in the normal case. The console is reading the output of your program and displaying it to the screen already.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
0

The reliable way is to use GetFinalPathNameByHandle to check the stdout file handle, if it's not redirected then an error will be returned

TCHAR chPath[MAX_PATH];
if (GetFinalPathNameByHandle(GetStdHandle(STD_OUTPUT_HANDLE), chPath, MAX_PATH, 0))
    std::cout << "stdout redirected to " << chPath << '\n';
else
    std::cout << "stdout not redirected" << '\n';

That API is available from Windows Vista onward. On older Windows GetMappedFileName needs to be used like this

phuclv
  • 37,963
  • 15
  • 156
  • 475