I want to write a console application that have a different behavior depending if the input is coming from keyboard or from, say, a file.
Is it possible? What's the most elegant way to do it in C#?
You can find out by p/invoking the Windows FileType() API function. Here's a helper class:
using System; using System.Runtime.InteropServices; public static class ConsoleEx { public static bool IsOutputRedirected { get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdout)); } } public static bool IsInputRedirected { get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdin)); } } public static bool IsErrorRedirected { get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stderr)); } } // P/Invoke: private enum FileType { Unknown, Disk, Char, Pipe }; private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 }; [DllImport("kernel32.dll")] private static extern FileType GetFileType(IntPtr hdl); [DllImport("kernel32.dll")] private static extern IntPtr GetStdHandle(StdHandle std); }
Usage:
bool inputRedirected = ConsoleEx.IsInputRedirected;
UPDATE: these methods were added to the Console class in .NET 4.5. Without attribution I might add :( Simply use the corresponding method instead of this helper class.
https://msdn.microsoft.com/en-us/library/system.console.isoutputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.isinputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.iserrorredirected.aspx
Interestingly, when a pipe is open, the System.Console.WindowHeight
and System.Console.WindowWidth
Parameters are zero, which I found out due to several ArgumentOutOfRangeException
's in code paths that did not care for the console size being zero.
Crossplatform: The behavior is the same under MS dotNET and Mono on Linux and Windows (I haven't tried it on a Mac).
When either STDIN or STDOUT are piped, the console size is set to 0. Thus building on Hans's implementation, my code is as follows:
using System; public static class ConsoleEx { public static bool IsConsoleSizeZero { get { try { return (0 == (Console.WindowHeight + Console.WindowWidth)); } catch (Exception exc){ return true; } } } public static bool IsOutputRedirected { get { return IsConsoleSizeZero && !Console.KeyAvailable; } } public static bool IsInputRedirected { get { return IsConsoleSizeZero && Console.KeyAvailable; } } }
Update 2016: Added exception handling to the IsConsoleSizeZero
Code to improve the usability of the code in a wider context.
The code still seems to work well, at least speaking from experience whilst using MonoDevelop / Xamarin Studio.
Related:
MSDN: KeyAvailable
Setting System.Console.WindowHeight throws an System.NotSupportedException under Mono.
Lorenz answer is a good beginning, but unfortunately can be used only a inspiration. There are more modes for running a console application.
Standard run (in console, without any redirection)
Everything work as expected in console.
Executing with redirection from console with standard input and/or standard output redirection
e.g.
type input_file.txt | application.exe
(in Windows), or application.exe <input_file.txt
for input redirection
(replace type
with cat
in Linux)
or
application.exe | grep pattern
or application.exe >output_file.txt
for output redirection
or
type input_file.txt | application.exe | grep pattern
or application.exe <input_file.txt >output_file.txt
for input and output redirection
Executing with redirection from console with standard output and error output redirection
e.g. application.exe >output_file.txt 2>error_file.txt
Executing with hidden console and redirected input/output/error
e.g. from a GUI application (console is not Visible at all)
Executing with hidden console without redirection of input/output/error
Each of these mode has it's own 'features'. The Console.WindowHeight
and Console.WindowWidth
work in Windows for the 1st and 2nd mode in the standard way. In Linux the return value in 2nd and 3rd mode is zero. Therefore in Linux you can not detect input only redirecting.
Therefore the code from Lorenz answer can not be used for detection of redirection in all cases. The IOException
when reading Console.WindowHeight
or Console.WindowWidth
is thrown only when there is no output to console (e.g. 3rd mode) and only for Windows.
To detect input redirection (in Windows only) use this function:
private static bool IsInputRedirected()
{
try
{
if (Console.KeyAvailable)
{
return (false);
}
}
catch (InvalidOperationException)
{
return (true);
}
return (false);
}
For all other redirection and operating systems... try to experiment how to detect them. Different console properties and functions 'work' (throw exception, or zero return values) for different modes.
Tested on Windows 7 .NET Framework 4 Client Profile
and Mono JIT compiler version 4.2.1 (Debian 4.2.1.102+dfsg2-7ubuntu4)
.
IMPORTANT:
Do not use this function for input redirecting in Linux (detect running OS/platform, e.g. Mono for Windows), because it can cause more trouble when you falsely expect redirection and the redirection is not active.
Since framework 4.5 exists the property Console.IsInputRedirected. 8-)
See Microsoft Docs:
https://docs.microsoft.com/en-us/dotnet/api/system.console.isinputredirected
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With